C++ 模板 - 浮点型和整型的不同特化
C++ Templates - Different Specialization for Floating and Integral types
我正在尝试编写一个带有如下签名的函数:
template<typename From, typename To>
To bar(From in){...}
此函数需要具有不同的行为,具体取决于 To
是浮点类型还是整数类型。 (假设From
是整数,都是算术)
这可以使用 if constexpr(std::is_integral<To>::value) {...} else {...}
轻松实现,但是我仅限于没有 if constexpr
.
的 C++11
实现这种专业化的好方法是什么?
您可以在 SFINAE 中使用模板重载。例如
template<typename To, typename From>
typename std::enable_if<std::is_integral<To>::value, To>::type bar(From in) {
...
}
template<typename To, typename From>
typename std::enable_if<std::is_floating_point<To>::value, To>::type bar(From in) {
...
}
顺便说一句,我建议更改模板参数From
和To
的声明顺序,然后您可以在调用它们时明确指定第一个模板参数。比如bar<int>(...);
和bar<float>(...);
.
如果您想获得除整型和浮点类型之外的更清晰的消息,您可以添加另一个重载。例如
template<class T> struct dependent_false : std::false_type {};
template<typename To, typename From>
typename std::enable_if<!std::is_integral<To>::value && !std::is_floating_point<To>::value, To>::type bar(From in) {
static_assert(dependent_false<To>::value, "Types must be integral or floating point types.");
}
如果您确定 To
类型是整型或浮点型,另一种可能的解决方案是使用标记调度
利用std::is_integral<T>
继承自std::true_type
,当T
为整型时,或继承自std::false_type
,否则可写bar()
(也使用 songyuanyao 建议的 From
/To
顺序更改)如下
template <typename To, typename From>
To bar (From inVal)
{ return foo<To>(inVal, std::is_integral<To>{}); }
并开发两个具有不同签名的foo()
模板函数(std::true_type
或std::false_type
用于第二个参数)如下
template <typename To, typename From>
To foo (From inVal, std::true_type const &)
{ std::cout << "foo() integral case: " << inVal << std::endl; return {0}; }
template <typename To, typename From>
To foo (From inVal, std::false_type const &)
{ std::cout << "foo() float case: " << inVal << std::endl; return {1}; }
现在打电话
bar<int>("abc");
bar<double>("xyz");
你得到
foo() integral case: abc
foo() float case: xyz
我正在尝试编写一个带有如下签名的函数:
template<typename From, typename To>
To bar(From in){...}
此函数需要具有不同的行为,具体取决于 To
是浮点类型还是整数类型。 (假设From
是整数,都是算术)
这可以使用 if constexpr(std::is_integral<To>::value) {...} else {...}
轻松实现,但是我仅限于没有 if constexpr
.
实现这种专业化的好方法是什么?
您可以在 SFINAE 中使用模板重载。例如
template<typename To, typename From>
typename std::enable_if<std::is_integral<To>::value, To>::type bar(From in) {
...
}
template<typename To, typename From>
typename std::enable_if<std::is_floating_point<To>::value, To>::type bar(From in) {
...
}
顺便说一句,我建议更改模板参数From
和To
的声明顺序,然后您可以在调用它们时明确指定第一个模板参数。比如bar<int>(...);
和bar<float>(...);
.
如果您想获得除整型和浮点类型之外的更清晰的消息,您可以添加另一个重载。例如
template<class T> struct dependent_false : std::false_type {};
template<typename To, typename From>
typename std::enable_if<!std::is_integral<To>::value && !std::is_floating_point<To>::value, To>::type bar(From in) {
static_assert(dependent_false<To>::value, "Types must be integral or floating point types.");
}
如果您确定 To
类型是整型或浮点型,另一种可能的解决方案是使用标记调度
利用std::is_integral<T>
继承自std::true_type
,当T
为整型时,或继承自std::false_type
,否则可写bar()
(也使用 songyuanyao 建议的 From
/To
顺序更改)如下
template <typename To, typename From>
To bar (From inVal)
{ return foo<To>(inVal, std::is_integral<To>{}); }
并开发两个具有不同签名的foo()
模板函数(std::true_type
或std::false_type
用于第二个参数)如下
template <typename To, typename From>
To foo (From inVal, std::true_type const &)
{ std::cout << "foo() integral case: " << inVal << std::endl; return {0}; }
template <typename To, typename From>
To foo (From inVal, std::false_type const &)
{ std::cout << "foo() float case: " << inVal << std::endl; return {1}; }
现在打电话
bar<int>("abc");
bar<double>("xyz");
你得到
foo() integral case: abc
foo() float case: xyz