我想根据模板参数yes
template <bool yes>
class Base {
public:
template<typename std::enable_if< yes, int>::type = 0>
Base() { /* yes */ }
template<typename std::enable_if<!yes, int>::type = 0>
Base() { /* no */ }
};
我很困惑为什么会产生编译器错误
failed requirement '!true'; 'enable_if' cannot be used to disable this declaration
在Base<true>
和
no type named 'type' in 'std::__1::enable_if<false, int>'; 'enable_if' cannot be used to disable this declaration
在Base<false>
上。我找不到其他任何变体,包括this和this和this也不起作用。如何基于yes
选择要使用的构造函数?
答案 0 :(得分:1)
这里有几个问题。第一件事是默认模板模板参数的语法错误,应该是:
template <bool yes>
class Base {
public:
template<typename T=std::enable_if< yes, int>::type>
Base() { /* yes */ }
template<typename T=std::enable_if<!yes, int>::type>
Base() { /* no */ }
};
但这也不起作用,因为默认参数值不是模板签名的一部分,因此,大致来说,这等效于:
template<typename T>
Base() { /* yes */ }
template<typename T>
Base() { /* no */ }
这就是两个构造函数的签名对编译器的外观。两者都是带有单个参数的模板,因此,出于重载解析的目的,两个构造函数都具有相同的签名,并且比声明两个“ Base(int foo)”构造函数要好得多。如果声明,将得到相同的错误
Base(int foo=0)
和
Base(int foo=1)
构造函数。两个构造函数都具有相同的签名。默认值不是签名的一部分。
有几种传统的方法可以解决此问题。 C ++库本身的常见设计模式是声明一些辅助空类,并将它们用作附加参数以消除不同方法的歧义,以实现重载解决方案。例如,使用std::in_place_t
为std::variant
's constructor的等效功能选择std::optional
或std::in_place_type_t
的特定重载构造函数。
在您的情况下,我们可以结合委托的构造函数来完全自动使用占位符参数:
#include <iostream>
struct bool_true {};
struct bool_false {};
template<bool value> class bool_value;
template<>
struct bool_value<true> {
typedef bool_true type;
};
template<>
struct bool_value<false> {
typedef bool_false type;
};
template<bool v>
using bool_value_t=typename bool_value<v>::type;
template <bool yes>
class Base {
public:
Base() : Base{ bool_value_t<yes>{} } {}
Base(const bool_true &)
{
std::cout << "Yes" << std::endl;
}
Base(const bool_false &)
{
std::cout << "No" << std::endl;
}
};
int main()
{
Base<true> t;
Base<false> f;
return 0;
}