Calling a free function instead of a method if it doesn't exist

前端 未结 4 851
滥情空心
滥情空心 2021-02-01 07:33

Suppose you have a family of type-unrelated classes implementing a common concept by means of a given method returning a value:

class A { public: int val() const         


        
4条回答
  •  青春惊慌失措
    2021-02-01 07:57

    The currently highest voted answer invokes undefined behavior in some cases, so I will give an alternative answer.

    We start with some boilerplate machinery:

    template struct type_sink { typedef void type; }
    template using TypeSink = typename type_sink::type;
    

    Then a has_val traits class:

    template
    struct has_val : std::false_type;
    template
    struct has_val().val()) > > : std::true_type;
    

    We can then use tag dispatching to solve your problem:

    template
    int val_of_internal( T const& t, std::true_type /* has_val */ ) {
      return t.val();
    }
    template
    int val_of_internal( T const& t, std::false_type /* has_val */ ) {
      return 0;
    }
    template
    int val_of( T const& t ) {
      return val_of_internal( t, has_val() );
    }
    

    If you find writing has_val tiresome and prefer macros, here is a set of macros that write the has_val for you:

    #define EXPRESSION_IS_VALID_FOR_TYPE_T_TRAIT( TRAIT_NAME, ... ) \
    template \
    struct TRAIT_NAME : std::false_type {}; \
    template \
    struct TRAIT_NAME< T, TypeSink< decltype( __VA_ARGS__ ) > >: std::true_type {}
    
    #define HAS_NULLARY_METHOD_TRAIT(TRAIT_NAME, METHOD_NAME) \
    EXPRESSION_IS_VALID_FOR_TYPE_T_TRAIT( TRAIT_NAME, std::declval().METHOD_NAME() )
    

    Now we can write this:

    HAS_NULLARY_METHOD_TRAIT( has_val, val );
    

    but I do not know if it is worth it.

提交回复
热议问题