使用`void_t`来检测多重继承类型的重复错误 [英] Using `void_t` to detect multiple inheritance type repetition errors

查看:213
本文介绍了使用`void_t`来检测多重继承类型的重复错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要实现 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

Example.

这篇关于使用`void_t`来检测多重继承类型的重复错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆