constexpr 的等效三元运算符 if?
Equivalent ternary operator for constexpr if?
也许我遗漏了什么,但我找不到任何提示:C++17 中是否有等同于 constexpr-if 的 constexpr 三元运算符?
template<typename Mode>
class BusAddress {
public:
explicit constexpr BusAddress(Address device) :
mAddress(Mode::write ? (device.mDevice << 1) : (device.mDevice << 1) | 0x01) {}
private:
uint8_t mAddress = 0;
};
不,没有 constexepr
条件运算符。但是你可以将整个东西包装在一个 lambda 中并立即对其进行评估(IIFE):
template<typename Mode>
class BusAddress {
public:
explicit constexpr BusAddress(Address device)
: mAddress([&]{
if constexpr (Mode::write) {
return device.mDevice << 1;
}
else {
return (device.mDevice << 1) | 0x01;
}
}())
{ }
private:
uint8_t mAddress = 0;
};
它可能不是有史以来最性感的代码,但它完成了工作。请注意,自 N4487 and P0170.
起,lambda 表达式默认为 constexpr
您似乎认为 if constexpr
是一种性能优化。 不是。如果将常量表达式放在 ?:
子句中,任何值得使用的编译器都会找出它解析的内容并删除条件。因此,对于特定的 Mode
.
,您编写的代码几乎肯定会编译成单个选项
if constexpr
的主要目的是完全消除另一个分支。也就是说,编译器甚至不检查它在语法上是否有效。这将适用于你 if constexpr(is_default_constructible_v<T>)
的事情,如果它是真的,你就会 T()
。对于常规 if
语句,如果 T
不是默认可构造的,即使周围的 if
子句是常量表达式,T()
仍然必须是语法上有效的代码。 if constexpr
删除该要求;编译器将丢弃不在其他条件下的语句。
对于 ?:
,这变得更加复杂,因为表达式的类型基于两个值的类型。因此,两个表达式都必须是合法的表达式,即使其中一个从未被求值。 ?:
的 constexpr
形式可能会丢弃未在编译时采用的替代方案。因此表达式的类型实际上应该只基于其中之一。
那是一种非常不同的东西。
为方便起见,也可以将已接受的答案翻译成模板函数:
#include <type_traits>
#include <utility>
template <bool cond_v, typename Then, typename OrElse>
decltype(auto) constexpr_if(Then&& then, OrElse&& or_else) {
if constexpr (cond_v) {
return std::forward<Then>(then);
} else {
return std::forward<OrElse>(or_else);
}
}
// examples
struct ModeFalse { static constexpr bool write = false; };
struct ModeTrue { static constexpr bool write = true; };
struct A {};
struct B {};
template <typename Mode>
auto&& test = constexpr_if<Mode::write>(A{}, B{});
static_assert(std::is_same_v<A&&, decltype(test<ModeTrue>)>);
static_assert(std::is_same_v<B&&, decltype(test<ModeFalse>)>);
const A a;
B b;
template <typename Mode>
auto&& test2 = constexpr_if<Mode::write>(a, b);
static_assert(std::is_same_v<const A&, decltype(test2<ModeTrue>)>);
static_assert(std::is_same_v<B&, decltype(test2<ModeFalse>)>);
也许我遗漏了什么,但我找不到任何提示:C++17 中是否有等同于 constexpr-if 的 constexpr 三元运算符?
template<typename Mode>
class BusAddress {
public:
explicit constexpr BusAddress(Address device) :
mAddress(Mode::write ? (device.mDevice << 1) : (device.mDevice << 1) | 0x01) {}
private:
uint8_t mAddress = 0;
};
不,没有 constexepr
条件运算符。但是你可以将整个东西包装在一个 lambda 中并立即对其进行评估(IIFE):
template<typename Mode>
class BusAddress {
public:
explicit constexpr BusAddress(Address device)
: mAddress([&]{
if constexpr (Mode::write) {
return device.mDevice << 1;
}
else {
return (device.mDevice << 1) | 0x01;
}
}())
{ }
private:
uint8_t mAddress = 0;
};
它可能不是有史以来最性感的代码,但它完成了工作。请注意,自 N4487 and P0170.
起,lambda 表达式默认为constexpr
您似乎认为 if constexpr
是一种性能优化。 不是。如果将常量表达式放在 ?:
子句中,任何值得使用的编译器都会找出它解析的内容并删除条件。因此,对于特定的 Mode
.
if constexpr
的主要目的是完全消除另一个分支。也就是说,编译器甚至不检查它在语法上是否有效。这将适用于你 if constexpr(is_default_constructible_v<T>)
的事情,如果它是真的,你就会 T()
。对于常规 if
语句,如果 T
不是默认可构造的,即使周围的 if
子句是常量表达式,T()
仍然必须是语法上有效的代码。 if constexpr
删除该要求;编译器将丢弃不在其他条件下的语句。
对于 ?:
,这变得更加复杂,因为表达式的类型基于两个值的类型。因此,两个表达式都必须是合法的表达式,即使其中一个从未被求值。 ?:
的 constexpr
形式可能会丢弃未在编译时采用的替代方案。因此表达式的类型实际上应该只基于其中之一。
那是一种非常不同的东西。
为方便起见,也可以将已接受的答案翻译成模板函数:
#include <type_traits>
#include <utility>
template <bool cond_v, typename Then, typename OrElse>
decltype(auto) constexpr_if(Then&& then, OrElse&& or_else) {
if constexpr (cond_v) {
return std::forward<Then>(then);
} else {
return std::forward<OrElse>(or_else);
}
}
// examples
struct ModeFalse { static constexpr bool write = false; };
struct ModeTrue { static constexpr bool write = true; };
struct A {};
struct B {};
template <typename Mode>
auto&& test = constexpr_if<Mode::write>(A{}, B{});
static_assert(std::is_same_v<A&&, decltype(test<ModeTrue>)>);
static_assert(std::is_same_v<B&&, decltype(test<ModeFalse>)>);
const A a;
B b;
template <typename Mode>
auto&& test2 = constexpr_if<Mode::write>(a, b);
static_assert(std::is_same_v<const A&, decltype(test2<ModeTrue>)>);
static_assert(std::is_same_v<B&, decltype(test2<ModeFalse>)>);