目前我有两个功能:
template<typename Type> bool f(Type* x);
template<typename... List> bool f(std::tuple<List...>* x);
有没有办法将这两个函数与一个额外的模板参数合并,该参数指示传递的类型是否为元组?
template<typename Type, bool IsTuple = /* SOMETHING */> bool f(Type* x);
答案 0 :(得分:13)
当然,使用is_specialization_of
(从here获取和修复的链接):
template<typename Type, bool IsTuple = is_specialization_of<Type, std::tuple>::value>
bool f(Type* x);
然而,问题是,你真的想要吗?通常,如果您需要知道类型是否为元组,则需要对元组进行特殊处理,这通常与其模板参数有关。因此,您可能希望坚持使用重载版本。
编辑:由于您提到您只需要专门的一小部分,我建议重载但仅适用于小的特殊部分:
template<class T>
bool f(T* x){
// common parts...
f_special_part(x);
// common parts...
}
与
template<class T>
void f_special_part(T* x){ /* general case */ }
template<class... Args>
void f_special_part(std::tuple<Args...>* x){ /* special tuple case */ }
答案 1 :(得分:5)
你可以让你的功能服从另一个功能:
template<typename Type,bool IsTuple> bool f(Type *x);
template<typename Type>
inline bool f(Type* x) { return f<Type,false>(x); }
template<typename... List>
inline bool f(std::tuple<List...>* x) { return f<std::tuple<List...>,true>(x); }
答案 2 :(得分:5)
使用C ++ 17,这是一个使用if constexpr
template <typename> struct is_tuple: std::false_type {};
template <typename ...T> struct is_tuple<std::tuple<T...>>: std::true_type {};
然后你可以做类似的事情:
template<typename Type> bool f(Type* x) {
if constexpr (is_tuple<Type>::value) {
std::cout << "A tuple!!\n";
return true;
}
std::cout << "Not a tuple\n";
return false;
}
确保其有效的测试:
f(&some_tuple);
f(&some_object);
输出:
一个元组!!
不是元组
部分来自此处answer
的How to know if a type is a specialization of std::vector?解决方案答案 3 :(得分:3)
对于C ++ 11,这是我的首选模式:
// IsTuple<T>()
template <typename T>
struct IsTupleImpl : std::false_type {};
template <typename... U>
struct IsTupleImpl<std::tuple <U...>> : std::true_type {};
template <typename T>
constexpr bool IsTuple() {
return IsTupleImpl<decay_t<T>>::value;
}
效果很好。没有依赖关系(我不能使用Boost)。
答案 4 :(得分:2)
可能会晚一点,但您也可以使用带有模板变量的更现代的c ++ 17样式执行以下操作:
template <typename T>
constexpr bool IsTuple = false;
template<typename ... types>
constexpr bool IsTuple<std::tuple<types...>> = true;
还有一些测试
struct TestStruct{};
static_assert(IsTuple<int> == false, "Doesn't work with literal.");
static_assert(IsTuple<TestStruct> == false, "Doesn't work with classes.");
static_assert(IsTuple<std::tuple<int, char>>, "Doesn't work with plain tuple.");
static_assert(IsTuple<std::tuple<int&, char&>>, "Doesn't work with lvalue references");
static_assert(IsTuple<std::tuple<int&&, char&&>>, "Doesn't work with rvalue references");
您可以在这里https://godbolt.org/z/FYI1jS
查看编辑: 您将需要运行std :: decay,std :: remove_volatile,std :: remove_const来处理特殊情况。