문제

나는 템플릿릭을 감지하는 경우에는 클래스가 특정 회원수의 서명이 있습니다.

문제와 유사한 여기에 인용 http://www.gotw.ca/gotw/071.htm 하지만 같은:항목에서의 서터의 책이라 그가 대답하는 질문 클래스 C 를 제공해야 합 회원 기능으로 특히 서명은,다른 프로그램지 않을 컴파일.에 내 문제가 뭔가를 할 필요가있는 경우 클래스에는 함수,다른 사람이"다른 것".

유사한 문제에 직면했으로 부스트::직렬화하지만 나도 좋아하지 않는 솔루션을 채택:템플릿 함수를 호출하는 기본적으로 무료로 기능을(당신이 정의)특정 서명을 정의하지 않는 경우 특히 멤버 함수(에서 그들의 경우에는"직렬화"는 2 개의 매개변수는 특정 유형의)특정 서명은,다른 컴파일한 오류가 발생합니다.는 것은 모두 구현하기 위해 간섭 및 비-관입 serialization.

내가 좋아하지 않는 솔루션을 위한 두 가지 이유:

  1. 비 침해를 재정의해야 합니다 세계적"직렬화"기능에 있는 부스트::serialization 네임스페이스,그래서 당신은 당신의 클라이언트을 열어 코드 네임스페이스의 향상 및 네임스페이스는 직렬화!
  2. 스택을 해결하는 엉망이 되었 10 12 함수 호출.

나를 정의할 필요가 맞춤 동작하는 클래스하지 않는 회원 기능 및 내 엔터티 내에 있는 다른 네임스페이스(그리고 내가 원하지 않을 재정의 글로벌 함수 정의에 하나의 네임스페이스를 사용하는 동안 또 다른 하나)

너는 나에게 힌트를 이 수수께끼를 해결하기 위해?

도움이 되었습니까?

해결책

나는 확실하지 않다면 나는 당신을 올바르게,하지만 당신을 악용할 수 있습 SFINAE 을 감지 기능이 존재에서 컴파일한다.예에서 나의 코드(을 테스트하는 경우스 클래스는 회원 기능 size_t 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;
}

내장 GCC4.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*() 자신의 오른쪽에있는 템플릿 및 인스턴스화하지 않는 "do 상속".

이러다가 영향을 미치지 않는 잘 알려진 SFINAE 접근 방식을 사용하여,"The 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* 가는 원하는 서명, 그리고 다시는 평가를 반환한 유형의 과부하.더 이상 "recursions"지금:그 std::true_type.

컴파일러하지 않 선택 /* SFINAE operator-exists :) */ 대 전화 test(0,0) 나지 않는 선택 /* SFINAE operator-has-correct-sig :) */ 전화 test(&A::operator*), 다음 두 경우에 그와 함께 간다 /* SFINAE game over :( */ 최종익 유형 std::false_type.

여기에는 테스트 프로그램을 보여줍니다 템플릿 생성 예상 응답에 다양한 샘플의 경우(GCC4.6.3again).

// 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,클래스,조합,또는 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;

체크에 대한 구성원 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 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)

이 충분해야 하는 경우에,당신의 이름을 알고 있는 멤버능합니다.(이 경우는,기능 즐 실패를 인스턴스화면 구성원이 없는 기능(쓰기를 작동 하는 것은 어쨌든 힘든 부족이 있기 때문이의 함수를 부분적인 전문화를 만들었습니다.를 사용해야 할 수 있습니다 템플릿 클래스)또한 활성화 구조체(과 유사 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>::valuetruefalse 의 목적을 위해 인라인 코드 또는 메타-프로그래밍입니다.

비-관입할 수 있습니다 serialize 에서의 네임스페이스 클래스는 연재된,또는 보관의 클래스,감사 Koenig 조회.보 네임스페이스에 대한 자유로운 기능 재정의 자세한 내용은.:-)

열어 주어진 네임스페이스를 구현하는 자유로운 기능은 완전히 잘못된 것입니다.(예를 들어,당신이하지 않을 열 네임스페이스 std 를 구현하는 swap 에 대한 당신의 자신의 형식만을 사용해야 Koenig 조회 대신 합니다.)

괜찮습니다.두 번째 시도합니다.그것은 그렇지 않으면 다음과 같이 하나,내가 찾는 것에 대한 더 많은 정보를 얻으시기 바랍니다.

나물 서터의 문서에 대해 이야기 특성.는지 이해할 수 있도록 특성을 클래스의 인스턴스화하는 기본은 대체 행동을,그리고 각 클래스에 대한 당신의 멤버 함수 존재,그 특성을 클래스 전문를 호출하는 멤버 함수입니다.내가 믿고 나물의 문서에서 언급하는 기술이 이를 수행되지 않도록의 많은 참여 복사 및 붙여넣기.

내가 말했듯이,하지만,아마도 당신을 원하지 않은 추가 작업과 관련된"태그"는 클래스를 구현하는 회원입니다.어떤 경우에,내가 찾는 것에서 세 번째는 솔루션입니다....

없는 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