假设我们有这样的元函数:
template<typename LHS , typename RHS> struct add;我们有一套专门的已知类型。 例如,整体包装:
template<typename T1 , T1 VALUE1 , typename T2 , T2 VALUE2> struct add<std::integral_constant<T1,VALUE1>,std::integral_constant<T2,VALUE2> : public std::integral_constant<std::common_type_t<T1,T2>,VALUE1+VALUE2> {}; //Take advantage of C++14 helpers几天前,我们创建了一个新类,我们专门为这个类增加了一些内容:
template<typename X , typename Y> struct point_2d { using x = X; using y = Y; }; template<typename X1 , typename Y1 , typename X2 , typename Y2> struct add<point_2d<X1,Y1>,ppoint_2d<X2,Y2>> : public point_2d<add<X1,X2>,add<Y1,Y2>> {};正如你所看到的,我使用add metafuntion来执行坐标的添加。 因此,任何具有添加元函数专用的类型都可以用作point_2d坐标。
我的问题是: 有没有什么办法来检查一个模板是否具有特定类型的特化作为参数?
像这样的东西:
template<template<typename...> class TEMPLATE , typename... Ts> struct has_specialization; template<template<typename...> class TEMPLATE , typename... Ts> struct has_specialization<TEMPLATE<Ts...> /* TEMPLATE<Ts...> exists */ , Ts...> : public std::true_type {}; template<template<typename...> class TEMPLATE , typename... Ts> struct has_specialization<TEMPLATE<Ts...> /* TEMPLATE<Ts...> doesn't exists */ , Ts...> : public std::false_type {};Suppose we have a metafunction like this:
template<typename LHS , typename RHS> struct add;And we have a set of specializations for known types. For example, integral wrappers:
template<typename T1 , T1 VALUE1 , typename T2 , T2 VALUE2> struct add<std::integral_constant<T1,VALUE1>,std::integral_constant<T2,VALUE2> : public std::integral_constant<std::common_type_t<T1,T2>,VALUE1+VALUE2> {}; //Take advantage of C++14 helpersA few days ago, we create a new class, and we specialize addition for this class:
template<typename X , typename Y> struct point_2d { using x = X; using y = Y; }; template<typename X1 , typename Y1 , typename X2 , typename Y2> struct add<point_2d<X1,Y1>,ppoint_2d<X2,Y2>> : public point_2d<add<X1,X2>,add<Y1,Y2>> {};As you can see, I used add metafuntion to perform the addition of the coordinates. So any type that has a specialization for add metafunction can be used as point_2d coordinates.
My question is: Is there any way to check if a template has a specialization with a given type as argument?
Something like this:
template<template<typename...> class TEMPLATE , typename... Ts> struct has_specialization; template<template<typename...> class TEMPLATE , typename... Ts> struct has_specialization<TEMPLATE<Ts...> /* TEMPLATE<Ts...> exists */ , Ts...> : public std::true_type {}; template<template<typename...> class TEMPLATE , typename... Ts> struct has_specialization<TEMPLATE<Ts...> /* TEMPLATE<Ts...> doesn't exists */ , Ts...> : public std::false_type {};最满意答案
@BartekBanachewicz的想法是通过assert提供用户友好的编译器错误。 如果我可以检查(以下是point_2d示例),如果传递的坐标是可添加的(也就是说,add metafuncion的专门化是为该坐标定义的或未定义的),则可以提供更多可读的错误,如“该坐标不可添加。point_2d需要添加点的可加坐标“,而不是常见的可怕模板瞬时错误。
鉴于这是你问题的动机,这不是一个更简单和更直接的解决方案:
#include <type_traits> template<typename LHS , typename RHS> using cannot_add = std::integral_constant<bool,std::is_same<LHS,LHS>::value>; template<typename LHS , typename RHS> struct add { /* Assert some expressively named condition that is always false but is dependent on a template parameter. */ static_assert(!cannot_add<LHS,RHS>::value, "Types are not addable. Need specialization"); }; template<typename T1 , T1 VALUE1 , typename T2 , T2 VALUE2> struct add<std::integral_constant<T1,VALUE1>,std::integral_constant<T2,VALUE2>> : public std::integral_constant< typename std::common_type<T1,T2>::type, VALUE1+VALUE2 > {}; int main() { add<std::integral_constant<int,1>,std::integral_constant<int,2>> x; // Line 25 add<float,float> y; // Line 26 return 0; }GCC 4.8.1诊断:
main.cpp:26:19: required from here main.cpp:12:2: error: static assertion failed: Types are not addable. Need specializationClang 3.3诊断:
main.cpp:12:2: error: static_assert failed "Types are not addable. Need specialization" static_assert(!cannot_add<LHS,RHS>::value, ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ main.cpp:26:19: note: in instantiation of template class 'add<float, float>' requested here add<float,float> y; // Line 26 ^@BartekBanachewicz the idea is to provide user friendly compiler errors through asserts. If i can check (Following with the point_2d example) if the coordinates passed are addable (That is, a specialization of add metafuncion is or not defined for that coordinates), I can provide more readable errors like "That coordinates are not addable. point_2d needs addable coordinates for point addition", instead of the common horrible template instantation errors.
Given that this is the motivation of your question would not this be an easier and more direct solution:
#include <type_traits> template<typename LHS , typename RHS> using cannot_add = std::integral_constant<bool,std::is_same<LHS,LHS>::value>; template<typename LHS , typename RHS> struct add { /* Assert some expressively named condition that is always false but is dependent on a template parameter. */ static_assert(!cannot_add<LHS,RHS>::value, "Types are not addable. Need specialization"); }; template<typename T1 , T1 VALUE1 , typename T2 , T2 VALUE2> struct add<std::integral_constant<T1,VALUE1>,std::integral_constant<T2,VALUE2>> : public std::integral_constant< typename std::common_type<T1,T2>::type, VALUE1+VALUE2 > {}; int main() { add<std::integral_constant<int,1>,std::integral_constant<int,2>> x; // Line 25 add<float,float> y; // Line 26 return 0; }GCC 4.8.1 diagnoses:
main.cpp:26:19: required from here main.cpp:12:2: error: static assertion failed: Types are not addable. Need specializationClang 3.3 diagnoses:
main.cpp:12:2: error: static_assert failed "Types are not addable. Need specialization" static_assert(!cannot_add<LHS,RHS>::value, ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ main.cpp:26:19: note: in instantiation of template class 'add<float, float>' requested here add<float,float> y; // Line 26 ^更多推荐
发布评论