2016-07-03 2 views
2

Я хотел бы получить ошибку компилятора в случае, если я передам номер float моему классу, который ожидает int в коде ниже. Приведенный ниже код работает с GCC 4.9.3Проверка типов с использованием шаблонов во время компиляции

gcc -std=c++98 -O0 -g3 -Wall -Wextra -c -fmessage-length=0 

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

#include <iostream> 
template <typename T> 
class CheckValidity { 
    public: 
     CheckValidity(){}; 

     T isFoo(T variable) 
     { 
      T result = static_cast<T>(0); 
      if (variable > static_cast<T>(5)) 
      { 
       result = static_cast<T>(1); 
      } 
      return result; 
     }; 
}; 

int main() { 
    CheckValidity<int> checkValidityInt; 
    std::cout << checkValidityInt.isFoo(6.0f) << std::endl; 
    return 0; 
} 
+2

Is -std = C++ 98 жесткое требование, или вы можете использовать какой-либо более высокий стандарт?Какой-то тип 'typename std :: enable_if'-magic должен делать трюк, но я не уверен, что он доступен на C++ 98. – Kent

+0

@ Kent, я мог бы использовать до C++ 03. К сожалению, мой встроенный компилятор больше не поддерживает. – Eagle

ответ

2

Причина вы не получаете предупреждение сейчас, потому что значение 6.0ffloat может быть без потерь преобразуется в int. То есть вы не теряете точности во время преобразования, потому что 6.0 может быть точно представлено как 6. Компилятор знает об этом, потому что вы используете константы времени компиляции.

Если вы изменили его 6.1f, к примеру, вы должны получить предупреждение (если у вас есть -Wconversion включен):

int main() { 
    CheckValidity<int> checkValidityInt; 
    std::cout << checkValidityInt.isFoo(6.1f) << std::endl; 
    return 0; 
} 
In function 'int main()': 
20 : warning: conversion to 'int' alters 'float' constant value [-Wfloat-conversion] 
std::cout << checkValidityInt.isFoo(6.1f) << std::endl; 

Вы также можете получить предупреждение, если вы проходили переменную тип float, а не постоянный. Это означает, что предупреждение должно уловить любые потенциальные проблемы. Точное преобразование константы не является реальной проблемой.

Чтобы преобразовать это предупреждение в сообщение (убедитесь, что вы его не пропустите), также передайте флаг -Werror.

0

Сделать функцию-член функцией члена-шаблона. Это открывает несколько возможностей для работы с разными типами.


static_assert Использование и std::is_floating_point, чтобы убедиться, что функция не вызывается с использованием типов с плавающей точкой.

template <typename U> 
T isFoo(U variable) 
{ 
    static_assert(std::is_floating_point<U>::value == false, 
        "Can't handle floating point types"); 
    T result = static_cast<T>(0); 
    if (variable > static_cast<T>(5)) 
    { 
     result = static_cast<T>(1); 
    } 
    return result; 
}; 

Чтобы убедиться, что U и T того же типа, вы можете использовать std::is_same:

template <typename U> 
T isFoo(U variable) 
{ 
    static_assert(std::is_same<T, U>::value, 
        "Can't handle different types"); 
    T result = static_cast<T>(0); 
    if (variable > static_cast<T>(5)) 
    { 
     result = static_cast<T>(1); 
    } 
    return result; 
}; 

Чтобы быть в состоянии иметь дело с U быть производным типом T , вы можете использовать:

template <typename U> 
T isFoo(U variable) 
{ 
    static_assert(std::is_base_of<T, U>::value, 
        "Can't handle incompatible types"); 
    T result = static_cast<T>(0); 
    if (variable > static_cast<T>(5)) 
    { 
     result = static_cast<T>(1); 
    } 
    return result; 
}; 
+0

@CodyGray, я заметил ошибку сразу после того, как отправил ответ. Теперь это исправлено. –

2

Для C++ 98:

Один из способов добиться того, что вы хотите, чтобы требовать точного соответствия, чтобы иметь метод шаблона, который принимает любой тип, но всегда терпит неудачу из-за SFINAE:

template<typename U> 
    U isFoo(U variable) 
    { 
     typename CheckValidity::InvalidType x; 
    } 

Для C++ 11:

Вы можете использовать удаленный метод для достижения того же эффекта более чисто:

template<typename U> 
    U isFoo(U variable) = delete; 
0

Вы ча n use template специализация:

//Returns false in the default case 
template<typename V> 
bool isFoo(V) 
{ 
    return false; 
}; 

//Returns true if the type passed is T 
template<> 
bool isFoo<T>(T) 
{ 
    return true; 
} 

Переменная по-прежнему передается как параметр без имени, потому что она вам не нужна внутри. Он также по-прежнему используется, потому что isFoo<decltype(var)>() лучше, чем isFoo(var).


Если вы можете использовать C++ 11, используйте std::is_same или подобные конструкции:

//You need a separate type, because if you use T, you will just cast the result to T 
template<typename V> 
bool isFoo(V) 
{ 
    //Compare the types 
    return std::is_same<V, T>::value; 
}; 
0

Этот эффект лучше достигается, если вы просто оставить общий класс шаблона просто объявленный, но не определен и специализировать шаблонный класс определение для float. Я бы попытался поиграть с чем-то вроде списков типов ...

0

Похоже, вы хотите использовать std::is_integral в сочетании с static_assert.

В любой функции или шаблона класса вы хотите ограничить до целых чисел, вы можете позвонить:

static_assert(std::is_integral<T>::value, "Integer required."); 

Вы также можете быть заинтересованы в std::enable_if (или удобство ЬурейеЕ enable_if_t):

template <typename Integer, 
      typename = std::enable_if_t<std::is_integral<Integer>::value>> 

Вы можете использовать вызов static_assert с любым целочисленным постоянным выражением для генерации ошибки времени компиляции, если выражение ложно. Вы можете использовать enable_if, чтобы ограничить типы, с которыми может быть создан шаблон (также вызывая ошибку компилятора, если вы используете недопустимый тип).

Редактировать: Я просто заметил, что вы используете -std = C++ 98. Если вам нужно использовать этот стандарт, я могу удалить этот ответ. Но если вы можете использовать C++ 11, это будет лучше, чем вы можете сделать в более ранних стандартах.

+0

мой код должен работать во встроенной системе, поэтому я бы хотел избежать любых утверждений – Eagle

+1

Почему статические утверждения были бы проблемой во встроенной системе? Они не имеют абсолютно никакой стоимости во время выполнения и будут ловить ошибку во время компиляции. Кажется, именно то, что вы хотели бы для встроенной системы ... –

+0

Пожалуйста, не удаляйте свой ответ. Это (возможно) не полезно для первоначального апеллянта (если только он не убеждает его двигаться в это тысячелетие), но он, вероятно, будет полезен людям, которые ищут SO с похожим вопросом. –

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