Есть проблемный шаблонный метод который выполняет простые действия с объектами типа T ( например += или + или любой другой )
но для некоторых типов этот оператор не определен и компилятор выдает ошибку:
error C2679: binary '+=' : no operator found which takes a right-hand
operand of type 'Некоторый_тип'
template < typename T >
T Foo ( const T & value )
{
T buf += value;
return buf;
}
я могу использовать !std::is_same
есть ли возможность на этапе компиляции отсечь исключительные ситуации?
что-то вроде
template < typename T >
T Foo ( const T & value )
{
#if T Тот_самый_тип
T buf = value;
#else
T buf += value;
#endif
return buf;
}
я понимаю что могу сделать специализацию для шаблона, но делать ее из-за одной строчки кажется не оптимальным
PS: вариант должен подходить и для gcc и для msvs2010
Ответ
Если вам нужно различить, есть ли в типе T оператор +, вам придётся заняться метапрограммированием на шаблонах, известном как «шаблонная магия».
Итак, начнём. Во-первых, напишем вспомогательную структуру, которая определяет доступность сложения:
#include
template
// Эта функция скомпилируется всегда
template
public:
// test
Отлично, мы на полпути к решению. Теперь осталось воспользоваться им:
#include
template
// воспользуемся опять SFINAE, для этого применим стандартный
// шаблон enable_if. SFINAE работает лишь на шаблонных функциях,
// поэтому добавим фиктивный шаблон
// это скомпилируется только если has_addition
// а это скомпилируется только если has_addition
Всё!
Вот такой код
int main()
{
X
выдаёт
with addition
without addition
Обновление: К сожалению, компилятор Visual Studio 2010 не настолько продвинут, так что код пришлось упростить и сделать более прямолинейным. (Для Visual Studio 2013 переделки не нужны.) Вот результат:
// precompiled header Visual Studio
#include "stdafx.h"
#include
template
// нету declval, эмулируем вручную. сама функция, понятно, не нужна
template
template
public:
enum { value = sizeof(test
template
// нельзя использовать значения параметров шаблона по умолчанию
// используем явное указание шаблонного параметра, прячем в дополнительную функцию
void use(T t)
{
use_impl
private:
template
template
};
int main()
{
X
Наверняка @Abyx придумает решение поизящнее.
Комментариев нет:
Отправить комментарий