2014-01-20 1 views
0

Рассмотрим следующий класс, который проверяет, является ли указанный тип строкой, и использует свойства типа для вызова другой функции на основе результата. Оригинальный источник имеет тип зависимостей от Obj, это упрощенный пример:Определение типа выделения из реализации

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; 
}; 

Как бы идти о развязке определения (например, хранение его в example_inline.hpp) из класса без предоставления каждого типа признака случая Определение?

Идеальное решение будет выглядеть следующим образом:

// 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() { 
    // ... 
} 

// ... 

выше, очевидно, не представляется возможным. Одним из решений было бы отделить функцию type_trait от класса и поместить его в пространство имен деталей, но это означало бы, что я должен всегда передавать AnyObject (и в этом смысле все объекты, которые модифицируются функцией), чтобы он выглядел не очень элегантный.

Есть ли хорошее решение этой проблемы? Мне бы очень хотелось, чтобы заголовки, о которых идет речь, были легко читаемы, не загромождая их тоннами enable_if.

Спасибо за любой вклад в вопрос.

+0

Как насчет отправки тегов? – dyp

+0

@dyp Не знал об этой идиоме, но это идеальное решение :) Я помету ваш ответ, как прием, если вы хотите уточнить его для других людей, имеющих ту же проблему. – Robin

+0

Как насчет простой 'if'? В вашем примере, похоже, нет зависимости от фактического типа, поэтому оба вызова действительны, и вы можете просто использовать 'if (std :: is_same :: value)' .. – dyp

ответ

3

Вы можете перегрузить на основе возвращаемого значения 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>{}); 
    } 
}; 
+0

Который также называется отправкой тегов :) Но я не смог сформулировать свой ответ как хайку :( – dyp

2

В этом простом случае, вы можете также специализироваться doStuff от параметра шаблона шаблона класса:

#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