std::is_base_of 和 if 错误
std::is_base_of and error with if
我的模板有问题:
我有两个构造函数和方法:
.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;
在这个 if 中,我检查了 T 的类型,如果它是 std::string,我使用 StateSystem 中的方法将名称更改为数字。换句话说,如果 T 是 int,我不需要更改它,所以我立即将 T 分配给 state(state 是 int)。但是我的编译器检查了 dwo 选项并给我错误:
Severity Code Description Project File Line Suppression State
错误 C2440“=”:无法从 'std::string' 转换为 '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'
不用两种不同的方法可以修复吗?
std::is_base_of
是编译时的东西。例如,您应该将它与 static_assert
一起使用。 C++ 运行时的类型信息比较复杂,您应该使用 RTTI 或 dynamic_cast
之类的东西。
This answer给出了差异的答案。
问题是这里的if
声明...
if (std::is_base_of<std::string, T>::value)
...是 运行 时间分支。尽管 is_base_of
可以在编译时求值,但编译器被迫编译 if
语句的两个分支,即使它们的正确性依赖于 is_base_of
条件。
Can I repair it without two different methods?
C++17 引入了 if constexpr (...)
,它在 编译时 进行分支。这仍然需要两个分支都是可解析的,但只实例化与谓词匹配的分支。因此,未采用的分支可以是 "invalid",您的程序将按预期工作。
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 and Meeting C++ 2016 做了一个名为 "Implementing static
control flow in C++14" 的演讲,其中解释了 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;
}
我的模板有问题:
我有两个构造函数和方法: .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;
在这个 if 中,我检查了 T 的类型,如果它是 std::string,我使用 StateSystem 中的方法将名称更改为数字。换句话说,如果 T 是 int,我不需要更改它,所以我立即将 T 分配给 state(state 是 int)。但是我的编译器检查了 dwo 选项并给我错误:
Severity Code Description Project File Line Suppression State
错误 C2440“=”:无法从 'std::string' 转换为 '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'
不用两种不同的方法可以修复吗?
std::is_base_of
是编译时的东西。例如,您应该将它与 static_assert
一起使用。 C++ 运行时的类型信息比较复杂,您应该使用 RTTI 或 dynamic_cast
之类的东西。
This answer给出了差异的答案。
问题是这里的if
声明...
if (std::is_base_of<std::string, T>::value)
...是 运行 时间分支。尽管 is_base_of
可以在编译时求值,但编译器被迫编译 if
语句的两个分支,即使它们的正确性依赖于 is_base_of
条件。
Can I repair it without two different methods?
C++17 引入了 if constexpr (...)
,它在 编译时 进行分支。这仍然需要两个分支都是可解析的,但只实例化与谓词匹配的分支。因此,未采用的分支可以是 "invalid",您的程序将按预期工作。
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 and Meeting C++ 2016 做了一个名为 "Implementing static
control flow in C++14" 的演讲,其中解释了 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;
}