我想通过C ++标准类型特征切换传递的值。这是测试代码显示我的意思:
template<typename T>
T _func(T t, std::is_integral<T>||std::is_enum<T>)
{
return t;
}
template<typename T>
T _func(T t, std::is_floating_point<T>)
{
return t;
}
template<typename T>
T _func(T t, std::is_same<T, std::string>)
{
return t;
}
template<typename T>
T func(T t)
{
return _func(t, T)
}
当然没有用。我尽我所能测试并找到实现这个的方法:
int testint(int t){ return t;}
std::string testString(std::string t ){return t;}
float testreal(float t ){return t;}
template <typename T>
T test_string_type(T t, std::true_type) {
return testString(t);
}
template <typename T>
T test_string_type(T t, std::false_type) {
return t;
}
template<typename T>
T test_real_type(T t, std::true_type)
{
return testreal(t) ;
}
template<typename T>
T test_real_type(T t, std::false_type)
{
return test_string_type(t, std::is_same<T, std::string>());
}
template<typename T>
T test_enum_type(T t, std::true_type)
{
return testint(t) ;
}
template<typename T>
T test_enum_type(T t, std::false_type)
{
return test_real_type(t, std::is_floating_point<T>());
}
template<typename T>
T test_integer_type(T t, std::true_type)
{
return testint(t) ;
}
template<typename T>
T test_integer_type(T t, std::false_type)
{
return test_enum_type(t, std::is_enum<T>()) ;
}
template<typename T>
T test(T t)
{
return test_integer_type(t, std::is_integral<T>());
}
它有效,但代码真的很难看。 有什么聪明的方法可以解决这个问题吗?
答案 0 :(得分:3)
您可以使用SFINAE拒绝重载
template<typename T>
typename std::enable_if<std::is_integral<T>::value || std::is_enum<T>::value>::type
func(T t)
{
return t;
}
template<typename T>
typename std::enable_if<std::is_floating_point<T>::value>::type
func(T t)
{
return t;
}
template<typename T>
typename std::enable_if<std::is_same<T, std::string>::value>::type
func(T t)
{
return t;
}
或使用类似于您所显示的标签调度,但以不同方式处理替代方案以减少案例数量
namespace detail
{
template<typename T>
T func(T t, std::false_type /*is_string*/, std::false_type /*is_float*/, std::true_type /*is_int*/)
{
return t;
}
template<typename T>
T func(T t, std::false_type /*is_string*/, std::true_type /*is_float*/, std::false_type /*is_int*/)
{
return t;
}
template<typename T>
T func(T t, std::true_type /*is_string*/, std::false_type /*is_float*/, std::false_type /*is_int*/)
{
return t;
}
}
template<typename T>
T func(T t)
{
return detail::func(t, std::is_same<string, T>(),
std::is_floating_point<T>(),
std::integral_constant<bool, std::is_integral<T>::value || std::is_enum<T>::value>());
}
答案 1 :(得分:3)
仅供记录,在C ++ 17中,您可以使用if constexpr
:
template <typename T>
T func(T t) {
if constexpr (std::is_integral<T>::value || std::is_enum<T>::value) {
return t + 1;
} else if constexpr (std::is_floating_point<T>::value) {
return t + 2.5;
} else if constexpr (std::is_same<T, std::string>::value) {
return t + " suffix";
}
return t;
}
此代码在Clang 3.9和GCC 7中编译。
答案 2 :(得分:1)
您可以通过SFINAE实现这一目标
#include <iostream>
#include <type_traits>
#include <string>
using namespace std;
struct One {};
struct Two {};
struct Three {};
template <typename T,
typename std::enable_if_t<std::is_integral<T>::value
|| std::is_enum<T>::value>* = nullptr>
One _func(T)
{
return One{};
}
template<typename T,
typename std::enable_if_t<std::is_floating_point<T>::value>* = nullptr>
Two _func(T)
{
return Two{};
}
template<typename T,
typename std::enable_if_t<std::is_same<
std::decay_t<T>, std::string>::value>* = nullptr>
Three _func(T)
{
return Three{};
}
template<typename T>
auto func(T t)
{
return _func(t);
}
template <typename...>
struct WhichType;
int main() {
WhichType<decltype(func(1))>{};
WhichType<decltype(func(1.0))>{};
WhichType<decltype(func(std::string{}))>{};
return 0;
}
这里有几点需要了解,第一个是SFINAE以及它是如何工作的,但回答这个问题会让答案太长,而且我可能会比其他人做得更糟糕,所以这里有一个{ {1}}(http://en.cppreference.com/w/cpp/types/enable_if)这里是对SFINAE的引用(http://eli.thegreenplace.net/2014/sfinae-and-enable_if/)
此处需要注意的另一个重要事项是其中一个功能模板中的std::enable_if
。如果传入的类型是std::decay_t
,则代码将不再正确,因为const string&
为false。 std::is_same<const string&, std::string>::value
删除所有引用,const限定符和volatile限定符。见http://en.cppreference.com/w/cpp/types/decay
std::decay_t
模板是一种用于检查变量类型的技术,如Scott Meyers在Effective Modern C ++一书中所述。大多数编译器将输出一个错误,显示模板中事物的类型。因此,当您想知道表达式的类型时,它很有用。在这种情况下,它将输出函数的返回类型,允许您查看调用的函数。