std::integral_constant 背后的原因是什么?
What's the reason behind having std::integral_constant?
这个的真正用例是什么?
std::integral_constant
我可以理解这是一个值为 2 的包装器:
typedef std::integral_constant<int, 2> two_t
但为什么不直接使用 2 或用 2 定义一个 const int 值呢?
2
是值,而 two_t
是类型。它们是两种不同的抽象。每个都有其目的。
- 您不能在需要类型的地方使用
2
。
- 您不能在需要整数值的地方使用
two_t
。
更重要的是,std::true_type
和std::false_type
是std::integral_constant
使用最广泛的特化。它们广泛用于 type_traits
。
在某些情况下 std::integral_constant
非常有用。
其中之一是标签分发。例如,std::true_type
和 std::false_type
分别只是 std::integral_constant<bool, true>
和 std::integral_constant<bool, false>
。每个 type trait 派生自 std::true_type
或 std::false_type
,这会启用标签分发:
template <typename T>
int foo_impl(T value, std::true_type) {
// Implementation for arithmetic values
}
template <typename T>
double foo_impl(T value, std::false_type) {
// Implementation for non-arithmetic values
}
template <typename T>
auto foo(T value) {
// Calls the correct implementation function, which return different types.
// foo's return type is `int` if it calls the `std::true_type` overload
// and `double` if it calls the `std::false_type` overload
return foo_impl(value, std::is_arithmetic<T>{});
}
此外,模板元编程库通常只有类型列表的算法,而不是值列表。如果您想改为使用这些算法来获取值,则必须使用 std::integral_constant
之类的东西
下面的代码片段是我使用 std::integral_constant 创建一个 api 的一种方法,它采用通用值,但它还会在编译时检查您提供的值是否有效。
#include<iostream>
struct Value {};
struct Color {};
struct Size {};
struct Point {};
enum class Property {
Color,
StrokeColor,
Opacity,
Size,
Position,
};
class Dom {
public:
// give a single api to setValue
template<Property prop, typename AnyValue>
void setValue(const std::string &obj, AnyValue value){
setValue(std::integral_constant<Property, prop>{}, obj, value);
}
private:
// specialization for each property and value type pair.
void setValue(std::integral_constant<Property, Property::Color> type,
const std::string &obj,
Color col) {std::cout<<" update color property\n";}
void setValue(std::integral_constant<Property, Property::StrokeColor> type,
const std::string &obj,
Color col){std::cout<<" update stroke color property\n";}
void setValue(std::integral_constant<Property, Property::Opacity> type,
const std::string &obj,
Value opacity){std::cout<<" update opacity property\n";}
};
int main()
{
Dom domObj;
// try to update the color property of rect1 object inside layer1
domObj.setValue<Property::Color>("layer1.rect1", Color());
// compile time error expects Color value but given Size value
//domObj.setValue<Property::Color>("layer1.rect1", Size());
return 0;
}
这个的真正用例是什么?
std::integral_constant
我可以理解这是一个值为 2 的包装器:
typedef std::integral_constant<int, 2> two_t
但为什么不直接使用 2 或用 2 定义一个 const int 值呢?
2
是值,而 two_t
是类型。它们是两种不同的抽象。每个都有其目的。
- 您不能在需要类型的地方使用
2
。 - 您不能在需要整数值的地方使用
two_t
。
更重要的是,std::true_type
和std::false_type
是std::integral_constant
使用最广泛的特化。它们广泛用于 type_traits
。
在某些情况下 std::integral_constant
非常有用。
其中之一是标签分发。例如,std::true_type
和 std::false_type
分别只是 std::integral_constant<bool, true>
和 std::integral_constant<bool, false>
。每个 type trait 派生自 std::true_type
或 std::false_type
,这会启用标签分发:
template <typename T>
int foo_impl(T value, std::true_type) {
// Implementation for arithmetic values
}
template <typename T>
double foo_impl(T value, std::false_type) {
// Implementation for non-arithmetic values
}
template <typename T>
auto foo(T value) {
// Calls the correct implementation function, which return different types.
// foo's return type is `int` if it calls the `std::true_type` overload
// and `double` if it calls the `std::false_type` overload
return foo_impl(value, std::is_arithmetic<T>{});
}
此外,模板元编程库通常只有类型列表的算法,而不是值列表。如果您想改为使用这些算法来获取值,则必须使用 std::integral_constant
下面的代码片段是我使用 std::integral_constant 创建一个 api 的一种方法,它采用通用值,但它还会在编译时检查您提供的值是否有效。
#include<iostream>
struct Value {};
struct Color {};
struct Size {};
struct Point {};
enum class Property {
Color,
StrokeColor,
Opacity,
Size,
Position,
};
class Dom {
public:
// give a single api to setValue
template<Property prop, typename AnyValue>
void setValue(const std::string &obj, AnyValue value){
setValue(std::integral_constant<Property, prop>{}, obj, value);
}
private:
// specialization for each property and value type pair.
void setValue(std::integral_constant<Property, Property::Color> type,
const std::string &obj,
Color col) {std::cout<<" update color property\n";}
void setValue(std::integral_constant<Property, Property::StrokeColor> type,
const std::string &obj,
Color col){std::cout<<" update stroke color property\n";}
void setValue(std::integral_constant<Property, Property::Opacity> type,
const std::string &obj,
Value opacity){std::cout<<" update opacity property\n";}
};
int main()
{
Dom domObj;
// try to update the color property of rect1 object inside layer1
domObj.setValue<Property::Color>("layer1.rect1", Color());
// compile time error expects Color value but given Size value
//domObj.setValue<Property::Color>("layer1.rect1", Size());
return 0;
}