0

Lets consider the following class which checks if the type provided is a string and uses type traits to call a different function based on the result. The original source has type dependencies on Obj, this is a simplified example:

template <typename Obj> class example { public: template <bool IdIsString = std::is_same<std::string, Obj>::value> typename std::enable_if<IdIsString, void>::type doStuff() { this->object->doSomething(); } template <bool IdIsString = std::is_same<std::string, Obj>::value> typename std::enable_if<!IdIsString, void>::type doStuff() { this->object->doSomethingElse(); } private: AnyObject object; }; 

How would I go about decoupling the definition (e.g. storing it in a example_inline.hpp) from the class without providing each type trait case in the definition?

An ideal solution would look like this:

// header.hpp template <typename Obj> class example { public: void doStuff(); } // header_inline.hpp template <typename Obj> template <bool IdIsString = std::is_same<std::string, Obj>::value> typename std::enable_if<IdIsString, void>::type example::doStuff() { // ... } // ... 

The above is obviously not possible. One solution would be to decouple the type_trait function from the class and put it into a detail namespace but this would mean that I would have to always pass AnyObject (and in that sense, all objects that are modified by the function) to it which seems not very elegant.

Is there a good solution for this problem? I'd really like for the headers in question be easily readable without cluttering them with tons of enable_if's.

Thanks for any input on the matter.

4
  • What about tag dispatch? Commented Jan 20, 2014 at 16:42
  • @dyp Didn't know about that idiom, but it seems to be an ideal solution :) I'll mark your answer as accept in case you want to elaborate on it for other people having the same problem. Commented Jan 20, 2014 at 17:05
  • What about a simple if? In your example, there seems to be no dependence on the actual type, so both calls are valid and you could just use an if(std::is_same<std::string, Obj>::value).. Commented Jan 20, 2014 at 17:06
  • There are quite a few type dependencies in the original source, I just left it out of the function bodies. Tag dispatch is ideal for the code I'm working with, thanks again. Commented Jan 20, 2014 at 17:10

2 Answers 2

3

You can overload based on the return value of std::is_same:

template<typename T> class example { private: void doStuff(std::true_type) { obj->doSomething(); } void doStuff(std::false_type) { obj->doSomethingElse(); } public: void doStuff() { doStuff(std::is_same<T, std::string>{}); } }; 
Sign up to request clarification or add additional context in comments.

1 Comment

Which is also called tag dispatch :) But I failed to formulate my answer as a haiku :(
2

In this simple case, you could also specialize doStuff on the template parameter of the class template:

#include <iostream> #include <string> template<class T> struct example { void doStuff(); }; template<class T> void example<T>::doStuff() { std::cout<<"default\n"; } template<> void example<std::string>::doStuff() { std::cout<<"string\n"; } int main() { example<int>{}.doStuff(); example<std::string>{}.doStuff(); } 

Live example

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.