C 17如果用元组用constexpr()使用
C++17 if constexpr() usage with tuple
我正在使用启用C 17支持的VS2017。
我想尝试制作一个"变压器"类,当提供某个类型的类型时,它将转换类型,否则它将像原样返回变量。目标是将所有变量类型传递给变压器,并"隐藏"其变换。这样,呼叫者可以尝试改变一切,而不必担心变换是否需要,变压器会知道。
一个更完整的示例(从原始编辑):
class MyPoint
{
public:
int x = 0;
};
class NotMyPoint
{
public:
int x = 50;
};
template <typename T>
class ITransform
{
public:
virtual ~ITransform() {};
virtual T InTransform(const T &in) const = 0;
virtual T OutTransform(const T &out) const = 0;
//Check if the argument type is the same as this class type
template <typename X>
constexpr bool CanTransform() const
{
return std::is_same<X, T>::value;
}
};
class MyTransformer :
public ITransform<MyPoint>
{
public:
MyTransformer() = default;
virtual MyPoint InTransform(const MyPoint &in) const override
{
auto newPt = in;
newPt.x += 100;
return newPt;
}
virtual MyPoint OutTransform(const MyPoint &in) const override
{
auto newPt = in;
newPt.x -= 100;
return newPt;
}
};
template <class... TRANSFORMERS>
struct VariadicTransformer
{
constexpr VariadicTransformer() = default;
/** brief parse using validateParse but catch throw */
template <typename T>
inline T Transform(const T& in)
{
return TransformImpl<sizeof...(TRANSFORMERS)-1, T>(in);
}
private:
/// last attempt to find matching transformer at I==0, if it fails return the original value
template<std::size_t I = 0, typename T>
inline typename std::enable_if<I == 0, T>::type TransformImpl(const T &in) const
{
if (std::get<I>(transformers).CanTransform<T>())
return std::get<I>(transformers).InTransform(in);
else
return in;
}
/// attempt to find transformer for this type
template<std::size_t I = 0, typename T>
inline typename std::enable_if < I != 0, T>::type TransformImpl(const T &in) const
{
if (std::get<I>(transformers).CanTransform<T>())
return std::get<I>(transformers).InTransform(in);
else
return TransformImpl<I - 1, T>(in);
}
std::tuple<const TRANSFORMERS...> transformers;
};
//Example usage
VariadicTransformer<MyTransformer, MyTransformer> varTrans;
MyPoint myPoint;
NotMyPoint notMyPoint;
std::cout << myPoint.x << std::endl;
myPoint = varTrans.Transform(myPoint);
std::cout << myPoint.x << std::endl;
std::cout << notMyPoint.x << std::endl;
notMyPoint = varTrans.Transform<NotMyPoint>(notMyPoint);
std::cout << notMyPoint.x << std::endl;
return 0;
我的问题带有这一行:
if constexpr(std::get<I>(transformers).CanTransform<T>())
这不会编译并提供以下错误:
错误C2131:表达未评估为常数
注意:失败是由于其寿命以外的变量读取
引起的注意:请参阅"此'''
的用法cantransform函数应该是constexpr,std :: get&lt;#>(std :: tuple)应该是constexpr,所以我不确定其对这一行的投诉是什么。
也需要if constexpr来避免试图调用任何不符合转换当前类型的变压器,我希望这种情况掉落并返回原始类型。
关于导致此错误或我可以尝试的其他设计的任何建议?
一个方法调用仅当调用对象为 constexpr
时,只有constexpr
。如果调用对象不是constexpr
,则该方法仍将在运行时而不是编译时进行评估,因此不符合任何汇编评估的条件。
struct A {
int val;
constexpr A() : A(16) {}
constexpr A(int val) : val(val) {}
constexpr bool foo() const {return val > 15;}
};
int main() {
A a;
if constexpr(a.foo()) {
std::cout << "No point thinking about it; this won't compile!" << std::endl;
} else {
std::cout << "Again, the previous line doesn't compile." << std::endl;
}
constexpr A b;
if constexpr(b.foo()) {
std::cout << "This, however, will compile, and this message will be displayed!" << std::endl;
}
constexpr A c(13);
if constexpr(c.foo()) {
std::cout << "This will not be displayed because the function will evaluate to false, but it will compile!" << std::endl;
}
}
您需要确保可以制作TransformImpl
constexpr
,然后确保A
的实例TransformImpl
也为constexpr
。
,所以我无法解释为什么上一个选项不起作用。但是,但是,通过将CanTransForm函数变成其自己的独立函数,错误就消失了。
这最终有效:
template<typename X, typename T>
constexpr inline bool CanTransform()
{
return std::is_base_of<ITransform<T>, X>::value;
}
template <class... TRANSFORMERS>
struct VariadicTransformer
{
constexpr VariadicTransformer() = default;
template <typename T>
constexpr inline T Transform(const T& in) const
{
return TransformImpl<sizeof...(TRANSFORMERS)-1, T>(in);
}
private:
// last attempt to find matching transformer at I==0, if it fails return the original value
template<std::size_t I = 0, typename T>
constexpr inline typename std::enable_if<I == 0, T>::type TransformImpl(const T &in) const
{
if constexpr(CanTransform < std::tuple_element < I, std::tuple<TRANSFORMERS...>>::type, T >())
return std::get<I>(transformers).InTransform(in);
else
return in;
}
// attempt to find transformer for this type
template<std::size_t I = 0, typename T>
constexpr inline typename std::enable_if < I != 0, T>::type TransformImpl(const T &in) const
{
if constexpr(CanTransform < std::tuple_element < I, std::tuple<TRANSFORMERS...>>::type, T >())
return std::get<I>(transformers).InTransform(in);
else
return TransformImpl<I - 1, T>(in);
}
std::tuple<TRANSFORMERS...> transformers;
};
相关文章:
- 当一个值是非常量但用常量表达式初始化时使用constexpr
- 在非 constexpr 函数中作为左值传递的变量上使用 'constexpr' 函数
- 为什么这两段使用 constexpr、__PRETTY_FUNCTION__ 和 char * 的代码有不同的结果?
- 使用 constexpr 替换 #define 和 #ifdef 进行条件编译
- 如果在 lambda 中使用 Constexpr static_assert,哪个编译器是正确的?
- 使用constexpr + auto作为返回和参数类型的奇怪类型推导
- C++编译时使用 constexpr 字符数组指针分配静态数组?
- 我可以使用 constexpr 函数声明一个静态数组吗?
- 使用constexpr布尔测试的enable_if不起作用
- 在构造函数中使用 constexpr 成员
- MSVC使用constexpr-if从可变模板方法中的基本模板参数中吞下const
- 使用 constexpr-if 时出错:'constexpr'之前的预期'('
- 使用 constexpr 初始化 std.array 中的对象
- 有没有办法声明一个公共静态常量,该常量将使用 constexpr 在源文件中定义(有什么区别)?
- 使用 constexpr 作为 std::array size
- 使用constexpr的全局初始化顺序
- 在通用 lambda 中使用 constexpr-if 来确定参数的类型
- 在头文件中使用 constexpr
- 使用 constexpr 和 std::array 进行静态初始化来替换动态初始化的 std::vector 的闰年
- 使用 constexpr 或模板元编程简化较长的展开循环表达式