c++ - 使用 `void_t`检测多重继承类型重复错误

标签 c++ templates sfinae c++17 variadic-functions

我想实现一个 has_no_duplicates<...>评估为 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>... { };

// 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{};

我以为我可以使用 void_t “检测”这个错误,但我无法实现有效的解决方案 following the code samples from 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 { };

第三次尝试,我尝试延迟 dup_helper<...> 的扩展使用包装类 dup_helper作为模板模板参数,如 wrapper<dup_helper, ...>并将其扩展到 void_t 中.

不幸的是,我的所有尝试都导致上述错误始终阻止编译。

我假设这种类型的错误无法检测为“替换失败”,但我想确认一下。


使用 void_t 实际上无法检测到这种错误吗? ? (会不会一直编译失败?)

有没有办法在不导致编译失败的情况下检测到它? (或者仍然使用“多重继承技巧”的非 void_t 解决方法)?

最佳答案

正如@Canoninos 指出的那样,问题在于:

it isn't the declaration of dup_helper<T, T> which causes an error but its definition [...].

或者,在标准语中,错误发生在替换的“直接上下文”([temp.deduct]) 之外:

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 ]

此处实例化时发生错误dup_helper<float, float>所以不在“直接上下文”中。

一个与您非常接近的多重继承技巧涉及通过索引多个碱基来添加额外的继承层:

helper<<0, 1>, <float, float>>        
             +            
        +----+----+       
        v         v       
 ix<0, float>  ix<1, float>
        +         +       
        v         v       
     t<float>  t<float>   

这为我们提供了一个具有有效定义的辅助类,它可以被实例化但不能转换为它的最终基类,因为存在歧义:

static_cast<t<float>>(helper<...>{});  // Error, SFINAE-usable

Example .

关于c++ - 使用 `void_t`检测多重继承类型重复错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32017004/

相关文章:

c++ - 将 Objective C++ 用于 WatchKit

c++ - Mac OS X 拒绝创建我的 OpenGL 窗口

c++ - 模板类型定义的数组初始化

c++ - 交换原始指针和迭代器

c++ - 检查类是否具有特定成员函数的其他方法

c++ - 类型推导后函数模板中的替换顺序是否有任何保证?

c++ - 格式错误的 C++0x 代码或编译器错误?

c++ - 本地址因本地作用域而被破坏时,第三次调用 temp2->next 如何能够访问第二个节点的地址?

c++ - boost regex_search 找不到第一个匹配项

c++ - 为什么 C++ 中的参数匹配会忽略数组大小?