为了创建算法模板函数,我需要知道类中的x或X(和y或Y)是否是模板参数。当我的函数用于MFC CPoint类或GDI + PointF类或其他类时,它可能很有用。他们都使用不同的x。我的解决方案可以简化为以下代码:


template<int> struct TT {typedef int type;};
template<class P> bool Check_x(P p, typename TT<sizeof(&P::x)>::type b = 0) { return true; }
template<class P> bool Check_x(P p, typename TT<sizeof(&P::X)>::type b = 0) { return false; }

struct P1 {int x; };
struct P2 {float X; };
// it also could be struct P3 {unknown_type X; };

int main()
{
    P1 p1 = {1};
    P2 p2 = {1};

    Check_x(p1); // must return true
    Check_x(p2); // must return false

    return 0;
}

但是在GNU C ++中进行编译时,它无法在Visual Studio中编译。使用Visual Studio,我可以使用以下模板:


template<class P> bool Check_x(P p, typename TT<&P::x==&P::x>::type b = 0) { return true; }
template<class P> bool Check_x(P p, typename TT<&P::X==&P::X>::type b = 0) { return false; }

但它不能在GNU C ++中编译。有普遍的解决方案吗?

UPD:此处的结构P1和P2仅作为示例。可能有任何不明成员的课程。

P.S。请不要在这里发布C ++ 11解决方案,因为它们很明显且与问题无关。

有帮助吗?

解决方案

另一种方式就是这个,它依赖于 SFINAE表达式也是如此。如果名称查找导致歧义,编译器将拒绝模板

template<typename T> struct HasX { 
    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;
}; 

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

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

这是基于usenet上有人的精彩想法。

注意:HasX检查任何名为x的数据或函数成员,具有任意类型。引入成员名称的唯一目的是使成员名称查找可能存在歧义 - 成员的类型并不重要。

其他提示

这是一个比更简单的解决方案 Johannes Schaub - litb 一个。它需要C ++ 11。

#include <type_traits>

template <typename T, typename = int>
struct HasX : std::false_type { };

template <typename T>
struct HasX <T, decltype((void) T::x, 0)> : std::true_type { };

更新:一个简单的示例以及有关其工作原理的说明。

对于这些类型:

struct A { int x; };
struct B { int y; };

我们有 HasX&lt; A&gt; :: value == true HasX&lt; B&gt; :: value == false 。让我们看看为什么。

首先回想一下, std :: false_type std :: true_type 有一个 static constexpr bool 成员名为 value 分别设置为 false true 。因此,上面的两个模板 HasX 继承了这个成员。 ( std :: false_type 中的第一个模板和 std :: true_type 中的第二个模板。)

让我们从简单开始,然后一步一步地进行,直到我们得到上面的代码。

1)起点:

template <typename T, typename U>
struct HasX : std::false_type { };

在这种情况下,毫不奇怪: HasX 派生自 std :: false_type ,因此 HasX&lt; bool,double&gt; :: value == false HasX&lt; bool,int&gt; :: value == false

2)默认 U

// Primary template
template <typename T, typename U = int>
struct HasX : std::false_type { };

鉴于 U 默认为 int Has&lt; bool&gt; 实际上意味着 HasX&lt; bool,int&gt; 因此, HasX&lt; bool&gt; :: value == HasX&lt; bool,int&gt; :: value == false

3)添加专业化:

// Primary template
template <typename T, typename U = int>
struct HasX : std::false_type { };

// Specialization for U = int
template <typename T>
struct HasX<T, int> : std::true_type { };

通常,由于主模板, HasX&lt; T,U&gt; 派生自 std :: false_type 。但是, U = int 存在一个特殊化,它源自 std :: true_type 。因此, HasX&lt; bool,double&gt; :: value == false HasX&lt; bool,int&gt; :: value == true

由于 U 的默认值, HasX&lt; bool&gt; :: value == HasX&lt; bool,int&gt; :: value == true

4) decltype 和一种奇特的说法 int

这里有点偏离,但是,请耐心等待。

基本上(这不完全正确), decltype(expression)产生表达式的类型。例如, 0 的类型为 int ,因此 decltype(0)表示 int 。类似地, 1.2 具有类型 double ,因此, decltype(1.2)表示 double

考虑使用此声明的函数:

char func(foo, int);

其中 foo 是某种类类型。如果 f foo 类型的对象,则 decltype(func(f,0))表示 char func(f,0)返回的类型。

现在,表达式(1.2,0)使用(内置)逗号运算符,它按顺序计算两个子表达式(即第一个 1.2 然后 0 ),丢弃第一个值并产生第二个值。因此,

int x = (1.2, 0);

相当于

int x = 0;

将它与 decltype 放在一起得出 decltype(1.2,0)表示 int 。这里的 1.2 double 并没有什么特别之处。例如, true 的类型为 bool decltype(true,0)也表示 int

班级类型怎么样?对于instace, decltype(f,0)是什么意思?很自然地认为这仍然意味着 int ,但可能并非如此。实际上,逗号运算符可能存在重载,类似于上面的函数 func ,它接受 foo int 并返回。在这种情况下, decltype(foo,0) char

我们如何避免对t使用重载

我从问题重定向到此处被关闭作为这个副本。我知道这是一个旧线程,但我只是想建议一个与C ++ 11一起使用的替代(更简单?)实现。假设我们要检查某个类是否有一个名为 id 的成员变量:

#include <type_traits>

template<typename T, typename = void>
struct has_id : std::false_type { };

template<typename T>
struct has_id<T, decltype(std::declval<T>().id, void())> : std::true_type { };

就是这样。以下是它的使用方法( 实例 ) :

#include <iostream>

using namespace std;

struct X { int id; };
struct Y { int foo; };

int main()
{
    cout << boolalpha;
    cout << has_id<X>::value << endl;
    cout << has_id<Y>::value << endl;
}

使用几个宏可以使事情变得更简单:

#define DEFINE_MEMBER_CHECKER(member) \
    template<typename T, typename V = bool> \
    struct has_ ## member : false_type { }; \
    template<typename T> \
    struct has_ ## member<T, \
        typename enable_if< \
            !is_same<decltype(declval<T>().member), void>::value, \
            bool \
            >::type \
        > : true_type { };

#define HAS_MEMBER(C, member) \
    has_ ## member<C>::value

可以这样使用:

using namespace std;

struct X { int id; };
struct Y { int foo; };

DEFINE_MEMBER_CHECKER(foo)

int main()
{
    cout << boolalpha;
    cout << HAS_MEMBER(X, foo) << endl;
    cout << HAS_MEMBER(Y, foo) << endl;
}

更新:我最近使用我在原始答案中发布的代码完成了更多操作,因此我对此进行更新以考虑更改/添加内容。

以下是一些使用情况摘要: *所有这些的胆量更远

检查给定班级中的成员 x 。可以是var,func,class,union或enum:

CREATE_MEMBER_CHECK(x);
bool has_x = has_member_x<class_to_check_for_x>::value;

检查成员函数 void x()

//Func signature MUST have T as template variable here... simpler this way :\
CREATE_MEMBER_FUNC_SIG_CHECK(x, void (T::*)(), void__x);
bool has_func_sig_void__x = has_member_func_void__x<class_to_check_for_x>::value;

检查成员变量 x

CREATE_MEMBER_VAR_CHECK(x);
bool has_var_x = has_member_var_x<class_to_check_for_x>::value;

检查成员类 x

CREATE_MEMBER_CLASS_CHECK(x);
bool has_class_x = has_member_class_x<class_to_check_for_x>::value;

检查成员联合 x

CREATE_MEMBER_UNION_CHECK(x);
bool has_union_x = has_member_union_x<class_to_check_for_x>::value;

检查成员枚举 x

CREATE_MEMBER_ENUM_CHECK(x);
bool has_enum_x = has_member_enum_x<class_to_check_for_x>::value;

检查任何成员函数 x ,无论签名如何:

CREATE_MEMBER_CHECK(x);
CREATE_MEMBER_VAR_CHECK(x);
CREATE_MEMBER_CLASS_CHECK(x);
CREATE_MEMBER_UNION_CHECK(x);
CREATE_MEMBER_ENUM_CHECK(x);
CREATE_MEMBER_FUNC_CHECK(x);
bool has_any_func_x = has_member_func_x<class_to_check_for_x>::value;

OR

CREATE_MEMBER_CHECKS(x);  //Just stamps out the same macro calls as above.
bool has_any_func_x = has_member_func_x<class_to_check_for_x>::value;

详细信息和核心:

/*
    - Multiple inheritance forces ambiguity of member names.
    - SFINAE is used to make aliases to member names.
    - Expression SFINAE is used in just one generic has_member that can accept
      any alias we pass it.
*/

template <typename... Args> struct ambiguate : public Args... {};

template<typename A, typename = void>
struct got_type : std::false_type {};

template<typename A>
struct got_type<A> : std::true_type {
    typedef A type;
};

template<typename T, T>
struct sig_check : std::true_type {};

template<typename Alias, typename AmbiguitySeed>
struct has_member {
    template<typename C> static char ((&f(decltype(&C::value))))[1];
    template<typename C> static char ((&f(...)))[2];

    //Make sure the member name is consistently spelled the same.
    static_assert(
        (sizeof(f<AmbiguitySeed>(0)) == 1)
        , "Member name specified in AmbiguitySeed is different from member name specified in Alias, or wrong Alias/AmbiguitySeed has been specified."
    );

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

宏(El Diablo!):

<强> CREATE_MEMBER_CHECK:

//Check for any member with given name, whether var, func, class, union, enum.
#define CREATE_MEMBER_CHECK(member)                                         \
                                                                            \
template<typename T, typename = std::true_type>                             \
struct Alias_##member;                                                      \
                                                                            \
template<typename T>                                                        \
struct Alias_##member <                                                     \
    T, std::integral_constant<bool, got_type<decltype(&T::member)>::value>  \
> { static const decltype(&T::member) value; };                             \
                                                                            \
struct AmbiguitySeed_##member { char member; };                             \
                                                                            \
template<typename T>                                                        \
struct has_member_##member {                                                \
    static const bool value                                                 \
        = has_member<                                                       \
            Alias_##member<ambiguate<T, AmbiguitySeed_##member>>            \
            , Alias_##member<AmbiguitySeed_##member>                        \
        >::value                                                            \
    ;                                                                       \
}

<强> CREATE_MEMBER_VAR_CHECK:

//Check for member variable with given name.
#define CREATE_MEMBER_VAR_CHECK(var_name)                                   \
                                                                            \
template<typename T, typename = std::true_type>                             \
struct has_member_var_##var_name : std::false_type {};                      \
                                                                            \
template<typename T>                                                        \
struct has_member_var_##var_name<                                           \
    T                                                                       \
    , std::integral_constant<                                               \
        bool                                                                \
        , !std::is_member_function_pointer<decltype(&T::var_name)>::value   \
    >                                                                       \
> : std::true_type {}

<强> CREATE_MEMBER_FUNC_SIG_CHECK:

//Check for member function with given name AND signature.
#define CREATE_MEMBER_FUNC_SIG_CHECK(func_name, func_sig, templ_postfix)    \
                                                                            \
template<typename T, typename = std::true_type>                             \
struct has_member_func_##templ_postfix : std::false_type {};                \
                                                                            \
template<typename T>                                                        \
struct has_member_func_##templ_postfix<                                     \
    T, std::integral_constant<                                              \
        bool                                                                \
        , sig_check<func_sig, &T::func_name>::value                         \
    >                                                                       \
> : std::true_type {}

<强> CREATE_MEMBER_CLASS_CHECK:

//Check for member class with given name.
#define CREATE_MEMBER_CLASS_CHECK(class_name)               \
                                                            \
template<typename T, typename = std::true_type>             \
struct has_member_class_##class_name : std::false_type {};  \
                                                            \
template<typename T>                                        \
struct has_member_class_##class_name<                       \
    T                                                       \
    , std::integral_constant<                               \
        bool                                                \
        , std::is_class<                                    \
            typename got_type<typename T::class_name>::type \
        >::value                                            \
    >                                                       \
> : std::true_type {}

<强> CREATE_MEMBER_UNION_CHECK:

//Check for member union with given name.
#define CREATE_MEMBER_UNION_CHECK(union_name)               \
                                                            \
template<typename T, typename = std::true_type>             \
struct has_member_union_##union_name : std::false_type {};  \
                                                            \
template<typename T>                                        \
struct has_member_union_##union_name<                       \
    T                                                       \
    , std::integral_constant<                               \
        bool                                                \
        , std::is_union<                                    \
            typename got_type<typename T::union_name>::type \
        >::value                                            \
    >                                                       \
> : std::true_type {}

<强> CREATE_MEMBER_ENUM_CHECK:

//Check for member enum with given name.
#define CREATE_MEMBER_ENUM_CHECK(enum_name)                 \
                                                            \
template<typename T, typename = std::true_type>             \
struct has_member_enum_##enum_name : std::false_type {};    \
                                                            \
template<typename T>                                        \
struct has_member_enum_##enum_name<                         \
    T                                                       \
    , std::integral_constant<                               \
        bool                                                \
        , std::is_enum<                                     \
            typename got_type<typename T::enum_name>::type  \
        >::value                                            \
    >                                                       \
> : std::true_type {}

<强> CREATE_MEMBER_FUNC_CHECK:

//Check for function with given name, any signature.
#define CREATE_MEMBER_FUNC_CHECK(func)          \
template<typename T>                            \
struct has_member_func_##func {                 \
    static const bool value                     \
        = has_member_##func<T>::value           \
        && !has_member_var_##func<T>::value     \
        && !has_member_class_##func<T>::value   \
        && !has_member_union_##func<T>::value   \
        && !has_member_enum_##func<T>::value    \
    ;                                           \
}

<强> CREATE_MEMBER_CHECKS:

//Create all the checks for one member.  Does NOT include func sig checks.
#define CREATE_MEMBER_CHECKS(member)    \
CREATE_MEMBER_CHECK(member);            \
CREATE_MEMBER_VAR_CHECK(member);        \
CREATE_MEMBER_CLASS_CHECK(member);      \
CREATE_MEMBER_UNION_CHECK(member);      \
CREATE_MEMBER_ENUM_CHECK(member);       \
CREATE_MEMBER_FUNC_CHECK(member)

Boost.ConceptTraits 其他一些宏之间提供定义类型特征,例如 BOOST_TT_EXT_DEFINE_HAS_MEMBER(name),它定义了表单的类型特征:

has_member_##name<T>

如果T具有名为的成员类型,则为true。但请注意,这不会检测引用类型成员。

在你的情况下,添加一个头文件就足够了

BOOST_TT_EXT_DEFINE_HAS_MEMBER_TYPE(x)

并检查如下

BOOST_STATIC_ASSERT(has_member_x<P1>::value);

使用的技术与上述某些答案中解释的技术相同。

不幸的是这个库不再维护了。现在C ++ 0x将不包含概念,这个库与SFINAE一起是一个完美的替代品,可以与大多数概念一起使用。

为什么不使用这样的专业化:

struct P1 {int x; };
struct P2 {int X; };

template<class P> 
bool Check_x(P p) { return true; }

template<> 
bool Check_x<P2>(P2 p) { return false; }

第二个答案(litb's)显示了如何检测成员:

是否可以编写模板进行检查功能的存在?

为什么不直接创建Check_x的模板特化?

template<> bool Check_x(P1 p) { return true; }
template<> bool Check_x(P2 p) { return false; }

哎呀,当我想起来的时候。如果您只有两种类型,为什么甚至需要模板?

是抽象基类的函数(x,X,y,Y),还是可以重构它们?如果是这样,你可以使用Modern C ++ Design中的SUPERSUBCLASS()宏,以及来自这个问题的答案的想法:

基于编译时类型的调度

我们可以在编译时获得: 0 - not_member,1 - is_object,2 - is_function ,用于每个必需的类和成员 - 对象或函数: http://ideone.com/Fjm9u5

#include <iostream>
#include <type_traits>

#define IS_MEMBER(T1, M)    \
struct {        \
    struct verystrangename1 { bool M; };    \
    template<typename T> struct verystrangename2 : verystrangename1, public T { }; \
    \
    enum return_t { not_member, is_object, is_function }; \
    template<typename T, typename = decltype(verystrangename2<T>::M)> constexpr return_t what_member() { return not_member;  }  \
    template<typename T> typename std::enable_if<std::is_member_object_pointer<decltype(&T::M)>::value, return_t>::type constexpr what_member() { return is_object; }   \
    template<typename T> typename std::enable_if<std::is_member_function_pointer<decltype(&T::M)>::value, return_t>::type constexpr what_member() { return is_function; }   \
    constexpr operator return_t() { return what_member<T1>(); } \
}

struct t {
    int aaa;
    float bbb;
    void func() {}
};

// Can't be in function
IS_MEMBER(t, aaa) is_aaa_member_of_t;
IS_MEMBER(t, ccc) is_ccc_member_of_t;
IS_MEMBER(t, func) is_func_member_of_t;

// known at compile time
enum { const_is_aaa_member_of_t = (int)is_aaa_member_of_t };
static constexpr int const_is_func_member_of_t = is_func_member_of_t;

int main() {        
    std::cout << std::boolalpha << "0 - not_member, 1 - is_object, 2 - is_function \n\n" <<
        "is aaa member of t = " << is_aaa_member_of_t << std::endl << 
        "is ccc member of t = " << is_ccc_member_of_t << std::endl << 
        "is func member of t = " << is_func_member_of_t << std::endl << 
        std::endl;

    return 0;
}

结果:

0 - not_member, 1 - is_object, 2 - is_function 

is aaa member of t = 1
is ccc member of t = 0
is func member of t = 2

对于class / struct:

struct t {
    int aaa;
    float bbb;
    void func() {}
};
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top