2013-04-29 2 views
0

Это псевдокод для того, что я хочу сделать.Как заставить клиента вызывать явно специализированный шаблон вместо основного шаблона?

template<typename T> 
struct ConvertToT 
{ 
    static_assert(false, "Explicit specialization for T required."); 

    // Variant will be coerced to this type before calling Convert. 
    std::uint32_t GetVariantType() 
    { 
     return VT_EMPTY; 
    } 
    T Convert(CComVariant& input) 
    { 
     return "ERROR!"; 
    } 
}; 

template<> 
struct ConvertToT<std::wstring> 
{ 
    std::uint32_t GetVariantType() 
    { 
     return VT_BSTR; 
    } 
    T Convert(CComVariant& input) 
    { 
     return std::wstring(input.bstrVal, ::SysStringLen(input.bstrVal)); 
    } 
}; 

/* repeat for several more explicit specializations: 
* template<> 
* struct ConvertToT<...> 
* { 
*  std::uint32_t GetVariantType() 
*  { 
*   return ...; 
*  } 
*  ... Convert(CComVariant& input) 
*  { 
*   return ...; 
*  } 
* }; 
*/ 

Есть ли способ отключить основной шаблон и потребовать использования явной специализации?

ответ

5

Да, просто не определить первичный шаблон:

template <typename> struct ConvertToT; 

template <> struct ConvertToT<int> 
{ 
    // ... 
}; 

// etc. 

Если вы хотите статическое утверждение, вы можете получить компилируемый код, как вы уже догадались, один дополнительный уровень косвенности:

template <typename> struct never_true : std::false_type { }; 

template <typename T> struct Foo 
{ 
    static_assert(never_true<T>::value, "Can't use this."); 
}; 

Это работает как для полных, так и для неполных типов.

(Вы также можете использовать !std::is_same<T, T>::value.)

+0

+1, и это работает. Но это не дает приятного сообщения, объясняющего, что произошло, например, 'static_assert', поэтому удерживая на ✓ на данный момент. –

+0

@BillyONeal: Отредактировано [здесь приведен пример] (http://ideone.com/Tuiznb) , Ключ должен сделать что-то зависимое от параметра шаблона. Я бы назвал этот метод «инъекцией зависимостей». –

+0

Это хорошо. И я могу даже сделать 'Foo''' WhileAttemptingConversionTo '' делая сообщение еще более ясным :) Спасибо! –

3

Самый простой способ, это просто не обеспечивает реализацию. Что-то вроде:

template <typename T> 
struct ConvertToT; 

template<> 
struct ConvertToT<SomeType> 
{ 
    // ... 
}; 

и так далее.

+0

«Внедрение» или «определение»? :-) –

+0

То же, что и ответ Керрека. Работает, но не дает сообщения, объясняющего, что произошло. :(+1 –

+0

@KerrekSB То же самое в этом случае, но определение более точно соответствует языку в стандарте. –

0

Вы можете оставить свой первоначальный подход, но enhace его с НЧ:

http://www.boost.org/doc/libs/1_36_0/libs/type_traits/doc/html/boost_typetraits/reference/is_class.html

template<typename T> 
struct ConvertToT 
{ 
    BOOST_STATIC_ASSERT_MSG(
    (boost::is_class<std::wstring, T>::value), 
    "T must be of wstring type" 
    ); 

    // Variant will be coerced to this type before calling Convert. 
    std::uint32_t GetVariantType() 
    { 
     return VT_EMPTY; 
    } 
    T Convert(CComVariant& input) 
    { 
    return "ERROR!"; 
    } 
}; 

Или, если вы используете C++ 11 использование зЬй :: is_class.

+0

Если бы я мог определить точный тип вещи, я бы не использовал шаблоны в первую очередь :) –

+0

Добавить в чек больше специализаций. Эти красиво печатают любую ошибку, допущенную пользователем, конечно, вы должны изменить проверку для каждого нового типа. Я должен признать, что это не чисто. – Trax

Смежные вопросы