区分不明确的成员请求错误和成员在SFINAE上下文中不存在错误?

Bre*_*ier 3 c++ templates ambiguity sfinae c++11

编辑:发布我自己的答案,保留原来接受的答案...让我思考别名.

编辑:我的问题是针对在SFINAE(或其他)上下文中区分模糊性与成员var/func存在的可能性.我的问题不是关于如何制作一个has_member模板,而是关于检测模糊与存在之间的区别

是否有可能设置部分特化,以区分何时以不明确的方式访问成员(派生类的基础都具有成员)vs成员是否存在(派生类的基础都不具有成员) ?我只有在检测到歧义时才需要返回true ,但如果根本没有成员,或者只存在一个类,则需要返回true .这是我到目前为止所返回的,它对于模糊性(我想要的)返回true,对于只有一个具有该成员的类(也是我想要的)返回false,但如果两个类都没有该成员则返回true(argh!)

//for the sake of this example, ClassOne comes from a lib I don't control
struct ClassOne {
    //some unknown members in here... 
};

struct ClassTwo {
    string member_var;
};

template<typename A>
struct helper : std::true_type {};

template<typename A, typename B>
struct merged_class : public A, public B {};

template<typename T, typename = void>
struct has_member_var : std::true_type {
    //Member request ambiguous or neither class has member.
    //I want to catch these conditions separately,
    //but this one template catches both :(
    const int status = 1;
};

template<typename T>
struct has_member_var<
    T
    , typename std::enable_if<
        //The next line results in either ambiguous member request error
        //if both classes have the member OR
        //member does not exist error if neither class has the member
        //...how to tell the difference in the type of error?
        helper<decltype(T::member_var)>::value
        , T
    >::type
> : std::false_type {
    const int status = 2; //only one class has member 
};

//This next one I have no idea how to do, if it's even possible.
//I'd like a third specialization that will match either the
//ambiguous condition or the member only existing in one of the
//base classes.
template<typename T>
struct has_member<
    T
    , typename std::enable_if<
        some_freaky_magic<decltype(T::foo)>::true_value
        , T
    >::type
> : std::true_type {
    const int status = 3;
};
Run Code Online (Sandbox Code Playgroud)

期望的用法:

switch(has_member<merged_class<ClassOne, ClassTwo>>::status) {
    case 1:
        cout << "member ambiguity";
        break;
    case 2:
        cout << "member non-existence";
        break;
    case 3:
        cout << "member existence for only one base";
        break;
}
Run Code Online (Sandbox Code Playgroud)

Ker*_* SB 6

好吧,我想我设法采用表达SFINAE方法并添加类型扣除.这是一个非常粗暴地被黑客攻击的答案,似乎做了一些有用的事情(参见底部的用法示例).

(演示文稿可能会更加简洁和干净,但这样你就可以看出它分为几步.)

用途: conflicting_X<A, B>::value为真当且仅当A,并B有一个名为成员x 该成员不同(严格,不腐烂)的类型.可以用conflicting_X<A, B>::both和决定中间问题,例如是否为两个类定义成员has_X<T>::value.

#include <iostream>
#include <type_traits>
#include <typeinfo>


// has_X is taken straight from the other topic

template <typename T>
struct has_X
{
  struct Fallback { int x; }; // introduce member name "x"
  struct Derived : T, Fallback { };

  template<typename C, C> struct ChT;

  template<typename C> static char (&f(ChT<int Fallback::*, &C::x>*))[1];
  template<typename C> static char (&f(...))[2];

  static bool const value = sizeof(f<Derived>(0)) == 2;
};

// Here we go...

template <typename T>
struct XType
{
  typedef decltype(T::x) type;
};

template <bool, typename S, typename T>
struct compare_X
{
  static const bool value = false;
};

template <typename S, typename T>
struct compare_X<true, S, T>
{
  // Note that we don't decay, we want equality on the nose.
  static const bool value =  ! std::is_same<typename XType<S>::type, typename XType<T>::type>::value;
};

template <typename S, typename T>
struct conflicting_X
{
  // We split this up so that XType is only instantiated if T::x really exists.
  // You may also use conflicting_X::both as a useful datum.
  static const bool both = has_X<S>::value && has_X<T>::value;
  static const bool value = compare_X<both, S, T>::value;
};


/*** Example ***/

struct A { int x; };
struct B { int X; };
struct C { double x; };

void f(double) { }

int main() {
  std::cout << has_X<A>::value << std::endl; // 1
  std::cout << has_X<B>::value << std::endl; // 0

  std::cout << "Conflict A/B? " << conflicting_X<A, B>::value << std::endl;
  std::cout << "Conflict A/C? " << conflicting_X<A, C>::value << std::endl;
}
Run Code Online (Sandbox Code Playgroud)