Vit*_*meo 8 c++ templates variadic-functions sfinae c++17
我想实现一个has_no_duplicates<...>类型特征,评估std::true_type传递的可变参数类型列表是否没有重复类型.
static_assert(has_no_duplicates<int, float>{}, "");
static_assert(!has_no_duplicates<float, float>{}, "");
Run Code Online (Sandbox Code Playgroud)
让我们假设,对于这个问题的范围,我想使用多重继承来做到这一点.
当一个类多次从同一类型继承时,会发生错误.
template<class T>
struct type { };
template<class... Ts>
struct dup_helper : type<Ts>... { };
// No errors, compiles properly.
dup_helper<int, float> ok{};
// Compile-time error:
// base class 'type<float>' specified more than once as a direct base class
dup_helper<float, float> error{};
Run Code Online (Sandbox Code Playgroud)
我以为我已经习惯于void_t"检测"这个错误,但是我无法在cppreference的代码示例之后实现一个有效的解决方案.
这是我试过的:
template<class, class = void>
struct is_valid
: std::false_type { };
// First try:
template<class T>
struct is_valid<T, std::void_t<decltype(T{})>>
: std::true_type { };
// Second try:
template<class T>
struct is_valid<T, std::void_t<T>>
: std::true_type { };
Run Code Online (Sandbox Code Playgroud)
对于我的第三次尝试,我尝试延迟dup_helper<...>使用dup_helper作为模板模板参数的包装类的扩展,wrapper<dup_helper, ...>并将其扩展为内部void_t.
不幸的是,我的所有尝试导致上述错误始终阻止编译.
我认为这种类型的错误不能被视为"替换失败",但我想要确认.
这种错误实际上是不可能使用void_t?(它总会导致编译失败吗?)
有没有办法检测它而不会导致编译失败?(或者void_t仍然使用"多重继承技巧" 的非解决方法)?
正如@Canoninos所说,问题在于:
它的定义不是
dup_helper<T, T>导致错误的声明,而是其定义[...].
或者,在Standardese中,错误发生在替换的"直接上下文"([temp.deduct])之外:
8 - [...]只有函数类型及其模板参数类型的直接上下文中的无效类型和表达式才会导致演绎失败.[ 注意:对替换类型和表达式的评估可能会导致副作用,例如类模板特化和/或函数模板特化的实例化,隐式定义函数的生成等.这些副作用不在"立即上下文"并且可能导致程序格式不正确.- 结束说明 ]
这里在实例化 时发生错误,dup_helper<float, float>因此不在"直接上下文"中.
一个非常接近你的多重继承技巧涉及通过索引多个基数来添加额外的继承层:
helper<<0, 1>, <float, float>>
+
+----+----+
v v
ix<0, float> ix<1, float>
+ +
v v
t<float> t<float>
Run Code Online (Sandbox Code Playgroud)
这给了我们一个带有有效定义的辅助类,可以实例化但不会强制转换为它的最终基类,因为它有歧义:
static_cast<t<float>>(helper<...>{}); // Error, SFINAE-usable
Run Code Online (Sandbox Code Playgroud)
例子.