使用`void_t`来检测多重继承类型的重复错误 [英] Using `void_t` to detect multiple inheritance type repetition errors
问题描述
我要实现 has_no_duplicates< ...>
type trait,计算结果为 std :: true_type
如果传递的可变参数类型列表没有重复类型。
static_assert(has_no_duplicates< int,float> {},);
static_assert(!has_no_duplicates< float,float> {},);
让我们假设,对于这个问题的范围,我想使用多重继承。
当类继承同一类型多次时,会发生错误。
template< class T>
struct type {};
template< class ... Ts>
struct dup_helper:type< Ts> ... {};
//没有错误,正确编译。
dup_helper< int,float>好{};
//编译时错误:
//基类class'type< float>'多次指定为直接基类
dup_helper< float,float&错误{};
我假设我可以使用 void_t
以检测此错误,但我无法实现工作解决方案遵循cppreference的代码示例 。
这是我试过的:
class = void>
struct is_valid
:std :: false_type {};
//首先尝试:
template< class T>
struct is_valid< T,std :: void_t< decltype(T {})>>
:std :: true_type {};
//第二次尝试:
template< class T>
struct is_valid< T,std :: void_t< T>>
:std :: true_type {};
对于第三次尝试,我试着延迟 dup_helper< 。>
使用包含 dup_helper
作为模板模板参数的包装类,如 wrapper< dup_helper,... < code>
不幸的是,在上述错误总是阻止编译。
我假设这种类型的错误不能被检测为替换失败,但我想确认。
这种错误实际上不可能使用 void_t
检测? (它总是会导致编译失败吗?)
有没有办法检测它而不导致编译失败? (or a non- void_t
解决方法仍然使用多继承技巧)?
正如@Canoninos所说,问题是:
$ c> dup_helper< T,T> 这会导致错误,但是它的定义[...]。
或者,在Standardese中,错误发生在替换的立即上下文( [temp.deduct] )之外:
8 - [...]只有在函数类型的立即上下文中的无效类型和表达式以及
它的模板参数类型才会导致扣除失败。 [注意:对替换类型
和表达式的求值会导致副作用,如类模板专用化实例化和/或
函数模板特化,隐式定义的函数的生成等。这样的副作用是不在直接上下文中的
,并且可能导致程序未成形。 - 结束注释]
在实例化 $ c> dup_helper< float,float> 所以不在立即上下文。
涉及通过索引多个基础来添加额外的继承层:
帮助<< 0,1>,< float ,float>>
+
+ ---- + ---- +
v v
ix< 0,float> ix< 1,float>
+ +
v v
t< float> t< float>
这给了我们一个有效定义的辅助类,可以实例化,基本类,因为模糊性:
static_cast< t< float>>(帮助< ...> {} ; //错误,SFINAE可用
示例。
I want to implement a has_no_duplicates<...>
type trait that evaluates to std::true_type
if the passed variadic type list has no duplicate types.
static_assert(has_no_duplicates<int, float>{}, "");
static_assert(!has_no_duplicates<float, float>{}, "");
Let's assume, for the scope of this question, that I want to do that using multiple inheritance.
When a class inherits from the same type more than once, an error occurs.
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{};
I assumed I could've used void_t
to "detect" this error, but I couldn't implement a working solution following the code samples from cppreference.
This is what I tried:
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 { };
For my third try, I tried delaying the expansion of dup_helper<...>
using a wrapper class that took dup_helper
as a template template parameter, like wrapper<dup_helper, ...>
and expanded it inside of void_t
.
Unfortunately, all my tries resulted in the aforementioned error always preventing compilation.
I assume this type of error is not detectable as a "substitution failure", but I'd like confirmation.
Is this kind of error actually impossible to detect using void_t
? (Will it always result in a compilation failure?)
Is there a way to detect it without causing compilation to fail? (Or a non-void_t
workaround that still makes use of the "multiple inheritance trick")?
As @Canoninos noted, the problem is that:
it isn't the declaration of
dup_helper<T, T>
which causes an error but its definition [...].
Or, in Standardese, the error occurs outside the "immediate context" ([temp.deduct]) of the substitution:
8 - [...] Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure. [ Note: The evaluation of the substituted types and expressions can result in side effects such as the instantiation of class template specializations and/or function template specializations, the generation of implicitly-defined functions, etc. Such side effects are not in the "immediate context" and can result in the program being ill-formed. — end note ]
Here the error occurs while instantiating dup_helper<float, float>
so is not in the "immediate context".
One multiple inheritance trick that's very close to yours involves adding an extra layer of inheritance, by indexing the multiple bases:
helper<<0, 1>, <float, float>>
+
+----+----+
v v
ix<0, float> ix<1, float>
+ +
v v
t<float> t<float>
This gives us a helper class with a valid definition and that can be instantiated but not cast to its ultimate base classes, because of ambiguity:
static_cast<t<float>>(helper<...>{}); // Error, SFINAE-usable
这篇关于使用`void_t`来检测多重继承类型的重复错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!