我们将这个名为std::conditional
的小编程奇迹描述为here。在同一参考文献中,它表示可能的实现是
template<bool B, class T, class F>
struct conditional { typedef T type; };
template<class T, class F>
struct conditional<false, T, F> { typedef F type; };
因此,如果在代码中我执行类似
的操作typename std::conditional<true,int,double>::type a;
编译器将遵循第一个定义,如果我执行类似
的操作typename std::conditional<false,int,double>::type b
编译器将采取第二个。为什么这样做?这里有什么编译规则?
答案 0 :(得分:7)
简而言之,它与模板专业化规则有关。这些类似于函数重载,但对于类型。
这里编译器更喜欢更通用的类型。
template<bool B, class T, class F>
struct conditional { typedef T type; };
template<class T, class F>
struct conditional<false, T, F> { typedef F type; };
因此,如果编译器看到模板实例化coditional<false, ...>
,它会找到:
template<bool B, class T, class F> struct conditional
template<class T, class F> struct conditional<false, T, F>
此时它会尝试匹配尽可能多的专用参数,最后选择false
专门化。
例如介绍另一个版本,如:
template<class F>
struct conditional<false, int, F> { typedef int type; };
并实例化类似conditional<false, int, double>
的模板类型将更喜欢专业化
template<class F> struct conditional<false, int, F>
到
template<class T, class F> struct conditional<false, T, F>
与具有2个专门参数的版本相比更为通用。
甚至可以声明最通用的情况(即模板的通用形式只是声明但未定义),并且只对您真正打算拥有的情况有专门化。所有非专业案例都会导致编译错误,并要求用户针对特定类型对案例进行专门化。
答案 1 :(得分:4)
为什么这样做?这里有什么编译规则?
我不是专家,但我会尝试从实际的角度来解释。
希望使用权利条款......
使用
template <bool B, class T, class F>
struct conditional { typedef T type; };
(但是,对于C ++ 11,我更喜欢
template <bool B, typename T, typename>
struct conditional { using type = T; };
)您声明模板
template <bool, typename, typename>
struct conditional;
并定义通用(非专用)版本。
用
template< class T, class F>
struct conditional<false, T, F> { typedef F type; };
(或者,在C ++ 11中,
template <typename T, typename F>
struct conditional<false, T, F> { using type = F; };
)定义conditional
当一个类(或结构)的模板参数匹配两个或多个定义时,编译器选择更专用的一个;所以,对于
typename std::conditional<false,int,double>::type
该类的两个定义都匹配,因此编译器选择专门的(false
专门)anche type
为double
。
有关
typename std::conditional<true,int,double>::type a;
只有通用版本匹配,因此type
为int
。
答案 2 :(得分:0)
在这里,大多数模板元编程的主要规则是SFINAE(替换失败不是错误)。根据此规则,如果编译器找不到类型,则它不会抛出错误,而是继续前进,并检查是否将来有任何语句可以提供类型信息。