我请求用一个模板招来检测,如果一类具有特定成员职能的给予的签名。

问题是相似的一个引这里 http://www.gotw.ca/gotw/071.htm 但不是相同的:在该项目的萨特的书,他回答了问题,一个C类必须提供一个成员能与某一特定签名,否则该程序不会编译。在我的问题我需要做一些事情,如果一类具有这一职能,还有什么"别的东西".

一个类似的问题,面临着通过提升::化,但我不喜欢的解决方案,他们通过:一个模板功能,调用默认情况下免费的功能(那你有定义),与一个特定的签名,除非你定义的特定部件的功能(在他们的情况"列化",需要2参数的定型)与一个特定的签字,还有一个编译错误会发生。这是实现这两个侵入性和非侵入性的序列化。

我不喜欢这种解决办法的原因有两个:

  1. 不能侵入你必须复盖全球的"化"的功能,在增强::化的名字空间,这样,你有你的客户代码打开名字空间的提升和名称空间序列化!
  2. 堆叠以解决, 混乱是10到12个功能调用。

我需要定义一个自定义的行为类别,还没有这件功能和我体内的不同的名字空间(并且我不想要复盖全球的功能定义在一个名字空间,而我在另一个之一)

你可以给我一个暗示的解决这个难题?

有帮助吗?

解决方案

我不知道,如果我理解正确,但你可以利用SFINAE检测功能存在在编译时间。例如从我的代码(如果测试类件的功能位置used_memory()const).

template<typename T>
struct HasUsedMemoryMethod
{
    template<typename U, size_t (U::*)() const> struct SFINAE {};
    template<typename U> static char Test(SFINAE<U, &U::used_memory>*);
    template<typename U> static int Test(...);
    static const bool Has = sizeof(Test<T>(0)) == sizeof(char);
};

template<typename TMap>
void ReportMemUsage(const TMap& m, std::true_type)
{
        // We may call used_memory() on m here.
}
template<typename TMap>
void ReportMemUsage(const TMap&, std::false_type)
{
}
template<typename TMap>
void ReportMemUsage(const TMap& m)
{
    ReportMemUsage(m, 
        std::integral_constant<bool, HasUsedMemoryMethod<TMap>::Has>());
}

其他提示

这里是一个可能实施依赖C++11功能。它正确地检测的功能,即使这是继承(不同于解决在公认的答案,作为迈克Kinghan注意到在 他的回答).

该功能的这段测试,用于称为 serialize:

#include <type_traits>

// Primary template with a static assertion
// for a meaningful error message
// if it ever gets instantiated.
// We could leave it undefined if we didn't care.

template<typename, typename T>
struct has_serialize {
    static_assert(
        std::integral_constant<T, false>::value,
        "Second template parameter needs to be of function type.");
};

// specialization that does the checking

template<typename C, typename Ret, typename... Args>
struct has_serialize<C, Ret(Args...)> {
private:
    template<typename T>
    static constexpr auto check(T*)
    -> typename
        std::is_same<
            decltype( std::declval<T>().serialize( std::declval<Args>()... ) ),
            Ret    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        >::type;  // attempt to call it and see if the return type is correct

    template<typename>
    static constexpr std::false_type check(...);

    typedef decltype(check<C>(0)) type;

public:
    static constexpr bool value = type::value;
};

使用:

struct X {
     int serialize(const std::string&) { return 42; } 
};

struct Y : X {};

std::cout << has_serialize<Y, int(const std::string&)>::value; // will print 1

接受回答这个问题的compiletime件的功能 自省,虽然是公正的受欢迎的,有一个障碍可以观察到 在以下程序:

#include <type_traits>
#include <iostream>
#include <memory>

/*  Here we apply the accepted answer's technique to probe for the
    the existence of `E T::operator*() const`
*/
template<typename T, typename E>
struct has_const_reference_op
{
    template<typename U, E (U::*)() const> struct SFINAE {};
    template<typename U> static char Test(SFINAE<U, &U::operator*>*);
    template<typename U> static int Test(...);
    static const bool value = sizeof(Test<T>(0)) == sizeof(char);
};

using namespace std;

/* Here we test the `std::` smart pointer templates, including the
    deprecated `auto_ptr<T>`, to determine in each case whether
    T = (the template instantiated for `int`) provides 
    `int & T::operator*() const` - which all of them in fact do.
*/ 
int main(void)
{
    cout << has_const_reference_op<auto_ptr<int>,int &>::value;
    cout << has_const_reference_op<unique_ptr<int>,int &>::value;
    cout << has_const_reference_op<shared_ptr<int>,int &>::value << endl;
    return 0;
}

建立与海湾合作委员会4.6.3、节目产出 110 -告诉我们 T = std::shared_ptr<int> 提供 int & T::operator*() const.

如果你是不是已经聪明到这个地方,然后看一看的定义 std::shared_ptr<T> 在头 <memory> 将摆脱光。在那 执行, std::shared_ptr<T> 是从一个基类 从它继承了 operator*() const.这样的模板的实例 SFINAE<U, &U::operator*> 这构成了"寻找"的操作员 U = std::shared_ptr<T> 不会发生,因为 std::shared_ptr<T> 有没有 operator*() 在其自己的权利和模板的实例不 "不继承".

这个障碍不影响众所周知的SFINAE的方法,使用"的sizeof()欺骗", 为检测是否仅仅是 T 有一些成员的功能 mf (例如见这个答案 和注释)。但 建立, T::mf 存在常常是(通常?) 不够好:你可以 还需要建立的,它具有所需的签名。这是哪里的 说明技术的成绩。该pointerized的变体所需的签名 被刻在一个参数的一个模型,必须满足 &T::mf 为SFINAE探针要取得成功。但是,这个模板的实例 技术给出了错误的答案时 T::mf 是遗传的。

安全SFINAE技术compiletime反省的 T::mf 必须避免的 使用 &T::mf 在一个模板参数的实例一种类型在这SFINAE 功能的模板决议的依赖。相反,SFINAE模板功能 决议可以依赖于只有在完全相关类型声明的使用 作为参数类型的超载SFINAE探测器的功能。

通过方式的一个问题的答案,遵守这个限制我 说明为compiletime检测 E T::operator*() const, , 任意 TE.同样的模式将适用 比照 以探测任何其他成员的方法的签名。

#include <type_traits>

/*! The template `has_const_reference_op<T,E>` exports a
    boolean constant `value that is true iff `T` provides
    `E T::operator*() const`
*/ 
template< typename T, typename E>
struct has_const_reference_op
{
    /* SFINAE operator-has-correct-sig :) */
    template<typename A>
    static std::true_type test(E (A::*)() const) {
        return std::true_type();
    }

    /* SFINAE operator-exists :) */
    template <typename A> 
    static decltype(test(&A::operator*)) 
    test(decltype(&A::operator*),void *) {
        /* Operator exists. What about sig? */
        typedef decltype(test(&A::operator*)) return_type; 
        return return_type();
    }

    /* SFINAE game over :( */
    template<typename A>
    static std::false_type test(...) {
        return std::false_type(); 
    }

    /* This will be either `std::true_type` or `std::false_type` */
    typedef decltype(test<T>(0,0)) type;

    static const bool value = type::value; /* Which is it? */
};

在这个解决方案,重载SFINAE探测器的功能 test() 是"调用 递归".(当然,它不是实际上援引;它仅仅是有 回归类型的假定的调用解决,通过编译器。)

我们需要探针对至少一个和至多两点的信息:

  • T::operator*() 存在呢?如果没有,我们正在这样做。
  • T::operator*() 存在,是其签名 E T::operator*() const?

我们得到的答案通过评估回返的种类型的一个单一的呼叫 要 test(0,0).这样做了:

    typedef decltype(test<T>(0,0)) type;

这一呼吁可能会被解决的 /* SFINAE operator-exists :) */ 超载 的 test(), 或者,它可能会解决的 /* SFINAE game over :( */ 超载。它不能解决的 /* SFINAE operator-has-correct-sig :) */ 过载, 因为这一期望只是一种说法,我们是通过两个。

为什么我们过两个人?简单地以武力解决以排除 /* SFINAE operator-has-correct-sig :) */.第二个论点没有其他signifance.

这个电话 test(0,0) 将决心 /* SFINAE operator-exists :) */ 只是 在情况下的第一个参数0satifies第一个参数的类型,重载, 这是 decltype(&A::operator*), 与 A = T.0将满足这一类型 只是在情况下 T::operator* 存在。

让我们假设编译器说的是这一点。然后就去 /* SFINAE operator-exists :) */ 它需要确定返回的类型 该功能的电话,在这种情况下是 decltype(test(&A::operator*)) - 回归类型的又一个呼叫 test().

这个时候,我们通过只是一个说法, &A::operator*, ,我们现在 知道存在,或者我们不会在这里.一个呼叫 test(&A::operator*) 可能会 要么解决 /* SFINAE operator-has-correct-sig :) */ 或再来 可能解决 /* SFINAE game over :( */.呼叫会比赛 /* SFINAE operator-has-correct-sig :) */ 只是在情况下 &A::operator* 满足 单参数类型,重载,这是 E (A::*)() const, 与 A = T.

编译器会说是的如果这里 T::operator* 有所需的签名, 然后再来评价的回报类型的超负荷。没有更多的 "递归"现在:它是 std::true_type.

如果编译器没有选择 /* SFINAE operator-exists :) */ 的 呼叫 test(0,0) 或者不选择 /* SFINAE operator-has-correct-sig :) */ 呼叫 test(&A::operator*), 然后无论在哪种情况下,它与去 /* SFINAE game over :( */ 并且最终返回的类型 std::false_type.

这是一个测试程序,显示了产生预期的模板 答案在不同的试样的情况下(海湾合作委员会4.6.3再)。

// To test
struct empty{};

// To test 
struct int_ref
{
    int & operator*() const {
        return *_pint;
    }
    int & foo() const {
        return *_pint;
    }
    int * _pint;
};

// To test 
struct sub_int_ref : int_ref{};

// To test 
template<typename E>
struct ee_ref
{
    E & operator*() {
        return *_pe;
    }
    E & foo() const {
        return *_pe;
    }
    E * _pe;
};

// To test 
struct sub_ee_ref : ee_ref<char>{};

using namespace std;

#include <iostream>
#include <memory>
#include <vector>

int main(void)
{
    cout << "Expect Yes" << endl;
    cout << has_const_reference_op<auto_ptr<int>,int &>::value;
    cout << has_const_reference_op<unique_ptr<int>,int &>::value;
    cout << has_const_reference_op<shared_ptr<int>,int &>::value;
    cout << has_const_reference_op<std::vector<int>::iterator,int &>::value;
    cout << has_const_reference_op<std::vector<int>::const_iterator,
            int const &>::value;
    cout << has_const_reference_op<int_ref,int &>::value;
    cout << has_const_reference_op<sub_int_ref,int &>::value  << endl;
    cout << "Expect No" << endl;
    cout << has_const_reference_op<int *,int &>::value;
    cout << has_const_reference_op<unique_ptr<int>,char &>::value;
    cout << has_const_reference_op<unique_ptr<int>,int const &>::value;
    cout << has_const_reference_op<unique_ptr<int>,int>::value;
    cout << has_const_reference_op<unique_ptr<long>,int &>::value;
    cout << has_const_reference_op<int,int>::value;
    cout << has_const_reference_op<std::vector<int>,int &>::value;
    cout << has_const_reference_op<ee_ref<int>,int &>::value;
    cout << has_const_reference_op<sub_ee_ref,int &>::value;
    cout << has_const_reference_op<empty,int &>::value  << endl;
    return 0;
}

有没有新的缺点在这样的想法?它可以作出更多的通用的而不再一次 下降的恶的障碍它避免了?

这里有一些使用情况的片段:*胆量对于所有这些是远下

检查员 x 在给定的类。可能是var,func、阶级、联盟或枚举:

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;

检查员enum 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;

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.
*/

//Variadic to force ambiguity of class members.  C++11 and up.
template <typename... Args> struct ambiguate : public Args... {};

//Non-variadic version of the line above.
//template <typename A, typename B> struct ambiguate : public A, public B {};

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恶魔!):

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)

这应该足够了,如果你知道的成员的名称的功能你期待。(在这种情况下,功能唠唠叨叨失败实例,如果没有成员的功能(编写一个工作无论如何是艰难的,因为缺乏功能部分专业化。你可能需要使用类模板)此外,该结构的启用(其是类似于enable_if)也可能模板类型的功能,你想让它有一个成员。

template <typename T, int (T::*) ()> struct enable { typedef T type; };
template <typename T> typename enable<T, &T::i>::type bla (T&);
struct A { void i(); };
struct B { int i(); };
int main()
{
  A a;
  B b;
  bla(b);
  bla(a);
}

这是一个简单的把迈克Kinghan的答复。这将检测到的继承的方法。它还将检查 确切的 签字(不同于jrok的办法,其中允许参数转换).

template <class C>
class HasGreetMethod
{
    template <class T>
    static std::true_type testSignature(void (T::*)(const char*) const);

    template <class T>
    static decltype(testSignature(&T::greet)) test(std::nullptr_t);

    template <class T>
    static std::false_type test(...);

public:
    using type = decltype(test<C>(nullptr));
    static const bool value = type::value;
};

struct A { void greet(const char* name) const; };
struct Derived : A { };
static_assert(HasGreetMethod<Derived>::value, "");

可运行的

你可以使用 std::is_member_function_pointer

class A {
   public:
     void foo() {};
}

 bool test = std::is_member_function_pointer<decltype(&A::foo)>::value;

来同样的问题我自己,找到了所提出的解决方案在这里非常有趣的...但是,已要求一个解决方案:

  1. 检测到继承的职能;
  2. 是兼容非C++11准备编译器(因此没有decltype)

找到另一个 螺纹 提出这样的事情,基于一个 提高讨论.这里是概括提出的解决方案为两个宏宣言》的特征类,下面的模型 提升::has_* 课程。

#include <boost/type_traits/is_class.hpp>
#include <boost/mpl/vector.hpp>

/// Has constant function
/** \param func_ret_type Function return type
    \param func_name Function name
    \param ... Variadic arguments are for the function parameters
*/
#define DECLARE_TRAITS_HAS_FUNC_C(func_ret_type, func_name, ...) \
    __DECLARE_TRAITS_HAS_FUNC(1, func_ret_type, func_name, ##__VA_ARGS__)

/// Has non-const function
/** \param func_ret_type Function return type
    \param func_name Function name
    \param ... Variadic arguments are for the function parameters
*/
#define DECLARE_TRAITS_HAS_FUNC(func_ret_type, func_name, ...) \
    __DECLARE_TRAITS_HAS_FUNC(0, func_ret_type, func_name, ##__VA_ARGS__)

// Traits content
#define __DECLARE_TRAITS_HAS_FUNC(func_const, func_ret_type, func_name, ...)  \
    template                                                                  \
    <   typename Type,                                                        \
        bool is_class = boost::is_class<Type>::value                          \
    >                                                                         \
    class has_func_ ## func_name;                                             \
    template<typename Type>                                                   \
    class has_func_ ## func_name<Type,false>                                  \
    {public:                                                                  \
        BOOST_STATIC_CONSTANT( bool, value = false );                         \
        typedef boost::false_type type;                                       \
    };                                                                        \
    template<typename Type>                                                   \
    class has_func_ ## func_name<Type,true>                                   \
    {   struct yes { char _foo; };                                            \
        struct no { yes _foo[2]; };                                           \
        struct Fallback                                                       \
        {   func_ret_type func_name( __VA_ARGS__ )                            \
                UTILITY_OPTIONAL(func_const,const) {}                         \
        };                                                                    \
        struct Derived : public Type, public Fallback {};                     \
        template <typename T, T t>  class Helper{};                           \
        template <typename U>                                                 \
        static no deduce(U*, Helper                                           \
            <   func_ret_type (Fallback::*)( __VA_ARGS__ )                    \
                    UTILITY_OPTIONAL(func_const,const),                       \
                &U::func_name                                                 \
            >* = 0                                                            \
        );                                                                    \
        static yes deduce(...);                                               \
    public:                                                                   \
        BOOST_STATIC_CONSTANT(                                                \
            bool,                                                             \
            value = sizeof(yes)                                               \
                == sizeof( deduce( static_cast<Derived*>(0) ) )               \
        );                                                                    \
        typedef ::boost::integral_constant<bool,value> type;                  \
        BOOST_STATIC_CONSTANT(bool, is_const = func_const);                   \
        typedef func_ret_type return_type;                                    \
        typedef ::boost::mpl::vector< __VA_ARGS__ > args_type;                \
    }

// Utility functions
#define UTILITY_OPTIONAL(condition, ...) UTILITY_INDIRECT_CALL( __UTILITY_OPTIONAL_ ## condition , ##__VA_ARGS__ )
#define UTILITY_INDIRECT_CALL(macro, ...) macro ( __VA_ARGS__ )
#define __UTILITY_OPTIONAL_0(...)
#define __UTILITY_OPTIONAL_1(...) __VA_ARGS__

这些宏扩大到一个特征类与以下原型:

template<class T>
class has_func_[func_name]
{
public:
    /// Function definition result value
    /** Tells if the tested function is defined for type T or not.
    */
    static const bool value = true | false;

    /// Function definition result type
    /** Type representing the value attribute usable in
        http://www.boost.org/doc/libs/1_53_0/libs/utility/enable_if.html
    */
    typedef boost::integral_constant<bool,value> type;

    /// Tested function constness indicator
    /** Indicates if the tested function is const or not.
        This value is not deduced, it is forced depending
        on the user call to one of the traits generators.
    */
    static const bool is_const = true | false;

    /// Tested function return type
    /** Indicates the return type of the tested function.
        This value is not deduced, it is forced depending
        on the user's arguments to the traits generators.
    */
    typedef func_ret_type return_type;

    /// Tested function arguments types
    /** Indicates the arguments types of the tested function.
        This value is not deduced, it is forced depending
        on the user's arguments to the traits generators.
    */
    typedef ::boost::mpl::vector< __VA_ARGS__ > args_type;
};

那么什么是典型使用一个可以做出这个吗?

// We enclose the traits class into
// a namespace to avoid collisions
namespace ns_0 {
    // Next line will declare the traits class
    // to detect the member function void foo(int,int) const
    DECLARE_TRAITS_HAS_FUNC_C(void, foo, int, int);
}

// we can use BOOST to help in using the traits
#include <boost/utility/enable_if.hpp>

// Here is a function that is active for types
// declaring the good member function
template<typename T> inline
typename boost::enable_if< ns_0::has_func_foo<T> >::type
foo_bar(const T &_this_, int a=0, int b=1)
{   _this_.foo(a,b);
}

// Here is a function that is active for types
// NOT declaring the good member function
template<typename T> inline
typename boost::disable_if< ns_0::has_func_foo<T> >::type
foo_bar(const T &_this_, int a=0, int b=1)
{   default_foo(_this_,a,b);
}

// Let us declare test types
struct empty
{
};
struct direct_foo
{
    void foo(int,int);
};
struct direct_const_foo
{
    void foo(int,int) const;
};
struct inherited_const_foo :
    public direct_const_foo
{
};

// Now anywhere in your code you can seamlessly use
// the foo_bar function on any object:
void test()
{
    int a;
    foo_bar(a); // calls default_foo

    empty b;
    foo_bar(b); // calls default_foo

    direct_foo c;
    foo_bar(c); // calls default_foo (member function is not const)

    direct_const_foo d;
    foo_bar(d); // calls d.foo (member function is const)

    inherited_const_foo e;
    foo_bar(e); // calls e.foo (inherited member function)
}

要做到这一点,我们将需要使用:

  1. 功能的模板超载 不同的回报类型根据该方法是否可用
  2. 按照元条件的 type_traits 头,我们将要返回 true_typefalse_type 从我们的超载
  3. 宣布 true_type 载有期待一个 intfalse_type 超载等可变的参数,以利用: "最低优先的省略号的转换过载决议"
  4. 在限定的规范模板的 true_type 功能,我们将使用 declvaldecltype 让我们检测功能的独立的回归类型的差异或重载之间的方法

你可以看到一个活生生的例子的信 在这里,. 但是我也会解释它如下:

我要检查是否存在一个功能,名为 test 这需要一种类型敞篷车从 int, 然后我需要声明这两个职能:

template <typename T, typename S = decltype(declval<T>().test(declval<int>))> static true_type hasTest(int);
template <typename T> static false_type hasTest(...);
  • decltype(hasTest<a>(0))::valuetrue (注意,没有必要创建特殊的功能处理的 void a::test() 过载, void a::test(int) 被接受)
  • decltype(hasTest<b>(0))::valuetrue (因为 int 是可转换到 double int b::test(double) 被接受的、独立的的回报类型)
  • decltype(hasTest<c>(0))::valuefalse (c 没有一种方法叫 test 接受一种类型敞篷车从 int 因此,这是不能接受的)

这种解决方案2的缺点:

  1. 需要每一个方法宣言》的对功能
  2. 创建了名字空间的污染,特别是如果我们要测试类似的名称,例如什么我们名字的功能想到测试 test() 方法?

所以重要,这些功能可以宣布在一个详细的名字空间,或者理想的是如果他们是唯一可使用的一类,他们应该被宣布为私人通过这一类。为此目的,我已经写了一个宏以帮助你抽象这样的信息:

#define FOO(FUNCTION, DEFINE) template <typename T, typename S = decltype(declval<T>().FUNCTION)> static true_type __ ## DEFINE(int); \
                              template <typename T> static false_type __ ## DEFINE(...); \
                              template <typename T> using DEFINE = decltype(__ ## DEFINE<T>(0));

你可以用这样的:

namespace details {
    FOO(test(declval<int>()), test_int)
    FOO(test(), test_void)
}

随后叫 details::test_int<a>::valuedetails::test_void<a>::value 会屈服 truefalse 对于内联的代码或间编程。

是非侵入性的,你也可以把 serialize 在空间的类序列化,或者档案流,谢谢 柯尼希查找.看看 名字空间的用于功能复盖 更多的细节。:-)

开放任何给定名称空间来实现一个免费的功能是完全错误的。(例如,你不应该打开namespace std 实施 swap 为自己的种类,但应该使用柯尼希查找,而不是。)

好的。第二次尝试。好吧如果你不喜欢这一个,我在寻找更多的想法。

药萨特的条约谈判的特征。所以你可以有一个特征类,其默认的实例有后备的行为,并对每类成员的功能而存在,那么特征类为专门援引成员的功能。我相信草药的文章中提到的技术要做到这一因此,它不涉及很多复印,并粘贴。

就像我说的,不过,也许你不想的额外工作涉及"标记"类做实施该成员。在这种情况下,我期待在第三个解决方案。...

没有C++11支持(decltype)这个可能的工作:

SSCCE

#include <iostream>
using namespace std;

struct A { void foo(void); };
struct Aa: public A { };
struct B { };

struct retA { int foo(void); };
struct argA { void foo(double); };
struct constA { void foo(void) const; };
struct varA { int foo; };

template<typename T>
struct FooFinder {
    typedef char true_type[1];
    typedef char false_type[2];

    template<int>
    struct TypeSink;

    template<class U>
    static true_type &match(U);

    template<class U>
    static true_type &test(TypeSink<sizeof( matchType<void (U::*)(void)>( &U::foo ) )> *);

    template<class U>
    static false_type &test(...);

    enum { value = (sizeof(test<T>(0, 0)) == sizeof(true_type)) };
};

int main() {
    cout << FooFinder<A>::value << endl;
    cout << FooFinder<Aa>::value << endl;
    cout << FooFinder<B>::value << endl;

    cout << FooFinder<retA>::value << endl;
    cout << FooFinder<argA>::value << endl;
    cout << FooFinder<constA>::value << endl;
    cout << FooFinder<varA>::value << endl;
}

如何,它希望工作

A, AaB 是这类的问题, Aa 是特殊的一个继承的成员,我们正在寻找的。

FooFindertrue_typefalse_type 是的替换的记者C++11课程。还对于理解的模板元编程,它们揭示的基础SFINAE-sizeof伎俩。

TypeSink 是一个模板中的结构是以后使用沉积的结果 sizeof 操作者进入一个模板的实例化,以形成一种类型。

match 功能是另一个SFINAE种模板,该模板也就没有一个通用的对应。它可能因此只要实例如果类型的论点相匹配的类型,这是专门为。

test 功能结合在一起,与枚举宣言的最后形式的中央SFINAE模式。有一个通用的一个用省略号的返回 false_type 和一个对应的更具体的论据具有优先地位。

能够实例 test 功能用一个模板参数的 T, , match 功能,必须实例,作为其返回的类型要求实例 TypeSink 参数。需要说明的是 &U::foo, ,被包裹在一个函数, 称从内的一个模板参数的专业化,所以继承的成员查找仍然发生。

我认为回答你在寻找的是在这里。

http://www.martinecker.com/wiki/index.php?title=Detecting_the_Existence_of_Operators_at_Compile-Time

和一个稍微更充满了例子在这里

http://pastie.org/298994

我使用的技术来检测是否存在一个支撑 ostream操作员 << 在这类问题,那么产生一个不同的代码。

我不相信它是可能之前找到相联系的解决方案,但它是一个非常整洁的伎俩。花时间了解代码,这是非常值得的。

布拉德

如果您使用facebook愚蠢的行为,他们被开箱的宏以帮助你:

#include <folly/Traits.h>
namespace {
  FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(has_test_traits, test);
} // unnamed-namespace

void some_func() {
  cout << "Does class Foo have a member int test() const? "
    << boolalpha << has_test_traits<Foo, int() const>::value;
}

虽然执行情况的详细信息是相同的,与以前的答复,使用图书馆是更简单。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top