Вопрос по c++ – Специализирующийся шаблон C ++, основанный на присутствии / отсутствии члена класса?

8

Учтите следующее:

<code>struct A {
  typedef int foo;
};

struct B {};

template<class T, bool has_foo = /* ??? */>
struct C {};
</code>

Я хочу специализировать C так, чтобы C & lt; A & gt; получает одну специализацию и C & lt; B & gt; получает другое, основываясь на наличии или отсутствии typename T :: foo. Возможно ли это с использованием черт типа или какой-либо другой магии шаблона?

Проблема состоит в том, что все, что я пробовал, приводит к ошибке компиляции при создании экземпляра C & lt; B & gt; потому что B :: foo не существует. Но это то, что я хочу проверить!

Редактировать: Я думаю, что ответ ildjarn лучше, но я наконец-то придумал следующее решение C ++ 11. Человек хакерский, но, по крайней мере, короткий. :)

<code>template<class T>
constexpr typename T::foo* has_foo(T*) {
  return (typename T::foo*) 1;
}
constexpr bool has_foo(...) {
  return false;
}
template<class T, bool has_foo = (bool) has_foo((T*)0)>
</code>
Вы должны были сказать, что заинтересованы в решении C ++ 11. : -] С тобой все в порядке, ноhas_foo(T*) перегрузка может быть улучшена путем возвратаbool и используя выражение SFINAE, поэтому не требуется приведение к месту вызова. ildjarn
(T*)0) должно бытьdeclval<T*>(), наверное Lol4t0

Ваш Ответ

2   ответа
6

template<typename T>
struct has_foo
{
private:
    typedef char no;
    struct yes { no m[2]; };

    static T* make();
    template<typename U>
    static yes check(U*, typename U::foo* = 0);
    static no check(...);

public:
    static bool const value = sizeof(check(make())) == sizeof(yes);
};

struct A
{
    typedef int foo;
};

struct B { };

template<typename T, bool HasFooB = has_foo<T>::value>
struct C
{
    // T has foo
};

template<typename T>
struct C<T, false>
{
    // T has no foo
};
2

has_member.

typedef char (&no_tag)[1]; 
typedef char (&yes_tag)[2];

template< typename T > no_tag has_member_foo_helper(...);

template< typename T > yes_tag has_member_foo_helper(int, void (T::*)() = &T::foo);

template< typename T > struct has_member_foo {
    BOOST_STATIC_CONSTANT(bool
        , value = sizeof(has_member_foo_helper<T>(0)) == sizeof(yes_tag)
        ); }; 

template<class T, bool has_foo = has_member_foo<T>::value> 
struct C {};

Похожие вопросы