3

Possible Duplicate:
Is it possible to write a C++ template to check for a function's existence?

In languages like JavaScript, you can check for the presence of a property

// javascript
if( object['property'] ) // do something

In C++, I want to condition compilation based on whether the type T has a certain property or not. Is this possible?

template <typename T>
class IntFoo
{
  T container ;
public:
  void add( int val )
  {
    // This doesn't work, but it shows what I'm trying to do.
    // if the container has a .push_front method/member, use it,
    // otherwise, use a .push_back method.
    #ifdef container.push_front
    container.push_front( val ) ;
    #else
    container.push_back( val ) ;
    #endif
  }

  void print()
  {
    for( typename T::iterator iter = container.begin() ; iter != container.end() ; ++iter )
      printf( "%d ", *iter ) ;

    puts( "\n--end" ) ;
  }
} ;

int main()
{
  // what ends up happening is 
  // these 2 have the same result (500, 200 --end).
  IntFoo< vector<int> > intfoo;
  intfoo.add( 500 ) ;
  intfoo.add( 200 ) ;
  intfoo.print() ;

  // expected that the LIST has (200, 500 --end)
  IntFoo< list<int> > listfoo ;
  listfoo.add( 500 ) ;
  listfoo.add( 200 ) ; // it always calls .push_back

  listfoo.print();
}
Community
  • 1
  • 1
bobobobo
  • 64,917
  • 62
  • 258
  • 363
  • 2
    Please see [This Question](http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence). – KitsuneYMG Oct 04 '12 at 14:58
  • Wow! "Substitution failure is not an error" (SFINAE)! – bobobobo Oct 04 '12 at 15:01
  • You can write a trait to check for the presence of a member function (at least in C++11). The [pretty printer](http://stackoverflow.com/q/4850473/596781) code contains an example of a trait for a `begin()` member function. – Kerrek SB Oct 04 '12 at 15:50

3 Answers3

5

The following example demonstrates a technique that can be used (in C++11, makes use of SFINAE for expressions):

typedef char no;
typedef no (&yes)[2];

no detect_push_front( ... );

template < class C >
auto detect_push_front( C &c ) -> typename std::conditional< false, decltype( c.push_front( std::declval< typename C::value_type >() ) ), yes >::type;

template < class C >
struct has_push_front : std::integral_constant< bool, sizeof( detect_push_front( std::declval< C & >() ) ) == sizeof( yes ) > {};

template < class C >
void add( C &c, typename C::value_type v, std::true_type )
{
    c.push_front( v );
}

template < class C >
void add( C &c, typename C::value_type v, std::false_type )
{
    c.push_back( v );
}

template < class C >
void add( C &c, typename C::value_type v )
{
    add( c, v, has_push_front< C >() );
}

int main()
{
    std::vector< int > v;
    add( v, 0 );
    add( v, 1 );
    add( v, 2 );
    std::copy( v.begin(), v.end(), std::ostream_iterator< int >( std::cout, " " ) );
    std::cout << '\n';

    std::list< int > l;
    add( l, 0 );
    add( l, 1 );
    add( l, 2 );
    std::copy( l.begin(), l.end(), std::ostream_iterator< int >( std::cout, " " ) );
    std::cout << '\n';
}

Output:

0 1 2
2 1 0
usta
  • 6,699
  • 3
  • 22
  • 39
  • You could add the name of this technique to increase the quality of your answer. – Sebastian Mach Oct 04 '12 at 16:45
  • Very nice. Other examples that describe SFINAE actually involve _runtime_ checks, but this is compile time overload resolution. – bobobobo Oct 04 '12 at 19:12
  • updavoted! - @bobobobo: Which ones? SFINAE is typically a compile-time thing, as it is typically related to overload resolution. (edit: I realise my typo in the first word, but found it so funny I just don't correct it) – Sebastian Mach Oct 05 '12 at 08:53
  • [This wikibooks example](http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Member_Detector) has a runtime check (which may be optimized out, but it's still an `if` statement) – bobobobo Oct 05 '12 at 17:27
1

As far as I know the only way you can achieve "conditional compilation" in C++ is by using preprocessor dircetives such as ifdef and ifndef. I don't any other technique exists.

Sidharth Mudgal
  • 4,234
  • 19
  • 25
1

You can't do that, but you can have something like

template<T,TT> void push_there(T& c,T& i) { c.push_back(i); }

And a partial specialization for container types that have push_front. Or the other way around.

Michael Krelin - hacker
  • 138,757
  • 24
  • 193
  • 173