2017-02-22 15 views
0

У меня есть проблема с шаблонами:станд :: is_base_of и ошибка, если

У меня два конструктора и метода: .cpp:

Cell::Cell(sf::Vector2i& uPos, sf::Vector2f& cellDimensions, std::string& stateName) 
    :unitPosition(uPos) 
{ 
    setBasicParameters<std::string>(stateName,cellDimensions,uPos); 
} 

Cell::Cell(sf::Vector2i & uPos, sf::Vector2f & cellDimensions, int stateNumber) 
    :unitPosition(uPos) 
{ 
    setBasicParameters<int>(stateNumber,cellDimensions,uPos); 
} 

.hpp ::

//Basic parameters which are being used by constructors 
    template < typename T = typename std::enable_if< std::is_base_of<int, T>::value, T>::type || typename std::enable_if< std::is_base_of<std::string, T>::value, T>::type> 
    void setBasicParameters(T& object, sf::Vector2f& cellDimensions, sf::Vector2i& uPos); 

template<typename T> 
inline void Cell::setBasicParameters(T& object, sf::Vector2f& cellDimensions, sf::Vector2i& uPos) 
{ 
    shape.setSize(cellDimensions); 
    shape.setOutlineThickness(cellDimensions.x/10.0f); //10% 

    shape.setOutlineColor(constants::cell::FILL_COLOR); 

    shape.setPosition(uPos.x*cellDimensions.x, uPos.y*cellDimensions.y); 

    if (!StateSystem::isStateExist(object)) 
    { 
     Logger::Log(constants::error::stateSystem::STATE_DOES_NOT_EXIST, Logger::STREAM::BOTH, Logger::TYPE::ERROR); 
     state = StateSystem::getNumberOfState(constants::defaults::EMPTY); 
    } 
    else 
    { 
     if (std::is_base_of<std::string, T>::value) 
      state = StateSystem::getNumberOfState(object); 
     else state = object; 

     setColor(StateSystem::getColorOfState(state)); 
    } 
} 

и проблема есть:

if (std::is_base_of<std::string, T>::value) 
      state = StateSystem::getNumberOfState(object); 
     else state = object; 

В этом случае, я проверяю тип T, и если это std :: string, я использую метод из StateSystem, который меняет имя на число. В противном случае, если T является int, мне не нужно изменять его, поэтому я сразу назначаю T для состояния (state is int). Но мой компилятор проверяет параметры DWO и дает мне ошибки:

Severity Code Description Project File Line Suppression State 

C2440 Ошибка «=»: не удается преобразовать из «станд :: строка» к «uint8_t»

Severity Code Description Project File Line Suppression State 
Error C2664 'int8_t mv::StateSystem::getNumberOfState(std::string)': cannot convert argument 1 from 'int' to 'std::string' 

Могу ли я восстановить его без сделать два разных метода?

ответ

3

Проблема заключается в том, что if утверждение здесь ...

if (std::is_base_of<std::string, T>::value) 

... это время выполнения ветви. Несмотря на то, что is_base_of можно оценить во время компиляции, компилятор вынужден скомпилировать обе ветви оператора if, даже если их правильность зависит от состояния is_base_of.


Могу ли я отремонтировать его без двух различных методов?

C++ 17 вводит if constexpr (...), который делает ветвления в время компиляции. Это по-прежнему требует, чтобы обе ветви были разобраны, но только создает экземпляр, соответствующий предикату. Поэтому невозвращенная ветка может быть «недействительной», и ваша программа будет работать, как ожидалось.

if constexpr (std::is_base_of<std::string, T>::value) 
    state = StateSystem::getNumberOfState(object); 
else state = object; 

Если у вас нет доступа к C++ 14, и вы действительно не хотите использовать две различные функции, вы можете реализовать эквивалентную конструкцию для if constexpr(...). Для реализации требуется значительное количество шаблонов.Окончательный результат будет выглядеть следующим образом:

static_if(std::is_base_of<std::string, T>{}) 
    .then([&](auto){ state = StateSystem::getNumberOfState(object); }) 
    .else_([&](auto){ state = object; })(_); 

Я прочитал лекцию на CppCon 2016 и Meeting C++ 2016 под названием «Реализация static потока управления в 14 C++», который объясняет, как static_if работает и как реализовать его самостоятельно.


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

if (!StateSystem::isStateExist(object)) 
{ 
    // ...as before... 
} 
else 
{ 
    dispatch(state, std::is_base_of<std::string, T>{}); 
    // ...as before... 
} 

Где dispatch определяется как:

void dispatch(State& state, Object& object, std::true_type) 
{ 
    state = StateSystem::getNumberOfState(object); 
} 

void dispatch(State& state, Object& object, std::false_type) 
{ 
    state = object; 
} 
+0

Вопрос: что происходит с sttic_if, что если T является производным от строки. Я могу себе представить, что встречаются те же проблемы, что и с static_cast для базового класса (заканчивается с временным?) – Swift

+0

@Swift: извините, но я не понимаю, что вы просите - можете ли вы показать пример минимального кода? Независимо от того, поведение 'static_if' должно быть эквивалентно' if constexpr', несмотря на менее заманчивый синтаксис. –

+0

@VittorioRomeo, я пробовал с if constexpr, но он дал мне 1 новую ошибку. Я использую сообщество Visual Studio 2015 https://scr.hu/6LXMY6 – mvxxx

0

std::is_base_of - вещь для компиляции. Например, вы должны использовать его с static_assert. Информация о типе во время выполнения на C++ является чем-то сложным, и вы должны использовать для этого такие вещи, как RTTI или dynamic_cast.

This answer дает ответы о различии.