使用SFINAE检测相同的类继承 [英] Detect same class inheritance with SFINAE

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

问题描述

我试图写一个元函数,检查作为一个可变参数传递的所有类型是否不同。似乎最好的方法是从一组类继承并检测是否有错误。



问题是编译失败

编辑。问题不是如何写的元功能,而是怎么做我发现双继承错误和输出 false_type 时发生。 AFAIK,只能使用SFINAE。






  template< typename T& 
struct dummy {};

//错误:重复基本类型'dummy< int>'无效
template< typename T,typename U>
struct fail:dummy< T>,dummy< U> {};

template< typename T>
true_type test(fail< T,T> a = fail< T,T&

false_type test(...);

int main(){
cout<< decltype(test< int>()):: value<< endl;
}

编辑。

我们试图用专业化失败做到这一点,但是它没有工作与编译错误。

  template<类型名T> 
struct dummy {};

template< typename T,typename U>
struct fail:dummy< T>,dummy< U>,true_type {};

template< typename T,typename U = void>
struct test:false_type {};

template< typename T>
struct test< T,typename enable_if< fail< T,T> :: value,void> :: type& :true_type {};

解决方案

您不能使用SFINAE捕获重复继承,因为它不是列出的14.8.2p8 [temp.deduct] 之下的扣除原因;同样,这是因为错误发生在模板扣除的直接上下文之外,因为它是你的 struct fail 实例化



然而,有一种非常类似的技术适用于您的情况,即检测来自派生类的模糊转换到多个基类。显然,模糊的基类不能直接从单个派生类继承,但它可以在线性链中继承它们:

  C<> A< int> 
| /
C< int> A< char>
| /
C< char,int> A< int>
| /
C< int,char,int>

现在转换 C A< int> 将是不明确的,并且作为模糊转换在14.8.2p8下列出,我们可以使用SFINAE来检测它:

  #include< type_traits> 

template< class> struct A {};
template< class ... Ts> struct C;
模板<> struct C<> {};
template< class T,class ... Ts>结构C< T,Ts ...> ;:A T,C< Ts ...> {};
template< class ... Ts> void f(A template< class ... Ts> std :: false_type g(...);
template< class ... Ts> (...),std :: true_type())g(int); ...,declare(f((A Ts(),C Ts ...
template< class ... Ts> using distinct = decltype(g< Ts ...>(0));

static_assert(distinct< int,char,float> :: value,!!);
static_assert(!distinct< int,char,int> :: value,!!);


I'm trying to write a metafunction that checks whether all types passed as a variadic template parameter are distinct. It seems that the most performant way to do this is to inherit from a set of classes and detect, whether there is an error.

The problem is that compilation fails in the following code, while I would expect SFINAE to work.

Edit. The question is not "how to write that metafunction" but "how do I catch that double inheritance error and output false_type when it happens". AFAIK, it's possible only with SFINAE.


template <typename T>
struct dummy {};

// error: duplicate base type ‘dummy<int>’ invalid
template <typename T, typename U>
struct fail : dummy<T>, dummy<U> {};

template <typename T>
true_type test(fail<T, T> a = fail<T, T>());

false_type test(...);

int main() {
    cout << decltype(test<int>())::value << endl;
}

Live version here.


Edit. Previously I've tried to do this with specialization failure, but it didn't work either with the same compilation error.

template <typename T>
struct dummy {};

template <typename T, typename U>
struct fail : dummy<T>, dummy<U>, true_type {};

template <typename T, typename U = void>
struct test : false_type {};

template <typename T>
struct test<T, typename enable_if<fail<T, T>::value, void>::type> : true_type {};

Live version here.

解决方案

You can't catch duplicate inheritance with SFINAE, because it is not one of the listed reasons for deduction to fail under 14.8.2p8 [temp.deduct]; equally, it is because the error occurs outside the "immediate context" of template deduction, as it is an error with the instantiation of your struct fail.

There is however a very similar technique which is suitable for use in your case, which is to detect an ambiguous conversion from a derived class to multiple base classes. Clearly the ambiguous base classes can't be inherited directly from a single derived class, but it works fine to inherit them in a linear chain:

C<> A<int>
|  /
C<int> A<char>
|     /
C<char, int> A<int>
|           /
C<int, char, int>

Now a conversion from C<int, char, int> to A<int> will be ambiguous, and as ambiguous conversion is listed under 14.8.2p8 we can use SFINAE to detect it:

#include <type_traits>

template<class> struct A {};
template<class... Ts> struct C;
template<> struct C<> {};
template<class T, class... Ts> struct C<T, Ts...>: A<T>, C<Ts...> {};
template<class... Ts> void f(A<Ts>...);
template<class... Ts> std::false_type g(...);
template<class... Ts> decltype(f((A<Ts>(), C<Ts...>())...), std::true_type()) g(int);
template<class... Ts> using distinct = decltype(g<Ts...>(0));

static_assert(distinct<int, char, float>::value, "!!");
static_assert(!distinct<int, char, int>::value, "!!");

这篇关于使用SFINAE检测相同的类继承的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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