3

So I was looking for ways to check whether a function with a particular argument exists. I have a templated method which relies on an external function (external from the class) to do the job:

  template <class Moo>
  void exportDataTo(Moo& ret){
     extended_solid_loader(ret, *this);
  }

At multiple points in the project I have macros which define extended_solid_loader for different types, but now I want to be able to use a default function if extended_solid_loader hasn't been defined for that particular class type.

I came across this: Is it possible to write a template to check for a function's existence? but it seems a little different, in that I'm not checking for a method, but rather a definition of a function with a particular argument type.

Is this possible right now?

Community
  • 1
  • 1
kamziro
  • 7,112
  • 7
  • 51
  • 74
  • Not a duplicate: http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence – krlmlr Nov 30 '13 at 22:21

2 Answers2

5

You can just provide a function template for extended_solid_loader providing a default implementation, and users who want to use something other than the default implementation just specialize that.

template<class T>
void extended_solid_loader(T & ret, SomeClass & obj) {
    // default implementation here
}

template<>
void extended_solid_loader<MooClass>(MooClass & ret, SomeClass & obj) {
    // special implementation for MooClass here
}
Björn Pollex
  • 70,106
  • 28
  • 177
  • 265
  • 1
    That's the ugly way. You have the issue of template function specialization and you have to specialize within the namespace the template's in as well. Unnecessary dependencies, etc... Just let ADL do it. – Edward Strange Jan 17 '11 at 20:30
2

You don't actually have to do anything particularly special. Just make sure there's a version of that function available to the template and let ADL do the dirty work. Check out this example:

#include <iostream>

namespace bob {

  struct X {};

  void f(X const&) { std::cout << "bob::f\n"; }
}

namespace ed {

  template < typename T >
  void f(T const&) { std::cout << "ed::f\n"; }

  template < typename T >
  struct test
  {
    void doit() // not called f and no other member so named.
    { f(T()); }
  };

}

int main()
{
  ed::test<int> test1;
  ed::test<bob::X> test2;

  test1.doit();
  test2.doit();

  std::cin.get();
}

Works without the namespace stuff too (non-templates have preference). I just used that to show that ADL will pick it up when you do.


Your original question was interesting. Found a way to do it in C++0x:

template < typename T >
struct fun_exists
{
  typedef char (&yes) [1];
  typedef char (&no)  [2];

  template < typename U >
  static yes check(decltype(f(U()))*);

  template < typename U >
  static no check(...);

  enum { value = sizeof(check<T>(0)) == sizeof(yes) };
};

void f(double const&) {}

struct test {};

#include <iostream>
int main()
{
  std::cout << fun_exists<double>::value << std::endl;
  std::cout << fun_exists<test>::value << std::endl;

  std::cin.get();
}
Edward Strange
  • 38,861
  • 7
  • 65
  • 123