是否有可能根据C++ 11中的C++ 11表达式是否为常量表达式(即constexpr
)生成编译时布尔值?关于SO的几个问题与此有关,但我在任何地方都没有看到直接答案.
考虑一个简单的INT Wrapper
与重载乘法类operator*=
和operator*
.对于"旧式"运算符重载,可以定义operator*
,operator*=
甚至还有像Boost.Operators这样的库以及@DanielFrey的现代化版本操作符,它们可以为您减少样板.
但是,对于使用新C++ 11的编译时计算constexpr
,这种便利性消失了.A constexpr operator*
无法调用,operator*=
因为后者修改了它的(隐式)左参数.此外,constexpr没有过载,因此constexpr operator*
在现有operator*
结果中添加额外的过载分辨率模糊.
我目前的做法是:
#include <iostream>
struct Wrap
{
int value;
Wrap& operator*=(Wrap const& rhs)
{ value *= rhs.value; return *this; }
// need to comment this function because of overloading ambiguity with the constexpr version
// friend Wrap operator*(Wrap const& lhs, Wrap const& rhs)
// { return Wrap { …
Run Code Online (Sandbox Code Playgroud) 我试图实现一个类似于std::is_constructible
异常的值模板,只有当类型在constexpr环境中可复制时才是真的(即它的复制构造函数是constexpr限定的).我到达了以下代码:
#include <type_traits>
struct Foo {
constexpr Foo() = default;
constexpr Foo(const Foo&) = default;
};
struct Bar {
constexpr Bar() = default;
Bar(const Bar&);
};
namespace detail {
template <int> using Sink = std::true_type;
template<typename T> constexpr auto constexpr_copiable(int) -> Sink<(T(T()),0)>;
template<typename T> constexpr auto constexpr_copiable(...) -> std::false_type;
}
template<typename T> struct is_constexpr_copiable : decltype(detail::constexpr_copiable<T>(0)){ };
static_assert( is_constexpr_copiable<Foo>::value, "");
static_assert(!is_constexpr_copiable<Bar>::value, "");
Run Code Online (Sandbox Code Playgroud)
现在我问自己这是否符合标准,因为编译器似乎不同意输出. https://godbolt.org/g/Aaqoah
编辑(c ++ 17功能):
在is_constexpr_constructible_from
使用c ++ 17的新的自动非类型模板类型实现稍微不同的时候,我再次发现编译器之间的区别,当在constexpr表达式中取消引用nullptr时SFINAE
.
#include <type_traits>
struct Foo …
Run Code Online (Sandbox Code Playgroud) 有没有办法constexpr
在编译阶段和运行时实现函数的不同行为?
考虑以下示例(使用理论特征D: static if
):
constexpr int pow( int base , int exp ) noexcept
{
static if( std::evaluated_during_translation() ) {
auto result = 1;
for( int i = 0 ; i < exp ; i++ )
result *= base;
return result;
} else { // std::evaluated_during_runtime()
return std::pow( base , exp );
}
}
Run Code Online (Sandbox Code Playgroud)
如果没有,有没有办法限制constexpr
只编译时间?
我之前根据参数是否constexpr
询问函数重载.我正试图解决这个问题的令人失望的答案,以建立一个更聪明的断言功能.这大致是我想做的事情:
inline void smart_assert (bool condition) {
if (is_constexpr (condition))
static_assert (condition, "Error!!!");
else
assert (condition);
}
Run Code Online (Sandbox Code Playgroud)
基本上,我们的想法是编译时检查总是比运行时检查更好,如果可以在编译时检查.但是,由于内联和常量折叠之类的东西,我不能总是知道是否可以进行编译时间检查.这意味着可能存在assert (condition)
编译的情况,assert(false)
代码只是等待我运行它并在我发现错误之前执行该路径.
因此,如果有某种方法来检查条件是否是constexpr(由于内联或其他优化),我可以static_assert
在可能的情况下调用,否则返回运行时断言.幸运的是,gcc具有内在函数__builtin_constant_p (exp)
,如果exp
是constexpr 则返回true .我不知道其他编译器是否有这种内在的,但我希望这可以解决我的问题.这是我提出的代码:
#include <cassert>
#undef IS_CONSTEXPR
#if defined __GNUC__
#define IS_CONSTEXPR(exp) __builtin_constant_p (exp)
#else
#define IS_CONSTEXPR(exp) false
#endif
// TODO: Add other compilers
inline void smart_assert (bool const condition) {
static_assert (!IS_CONSTEXPR(condition) or condition, "Error!!!");
if (!IS_CONSTEXPR(condition))
assert (condition);
}
#undef IS_CONSTEXPR
Run Code Online (Sandbox Code Playgroud)
该static_assert …
我可以在编译时检测"函数参数" 1是否是编译时常量?
例如,一个函数print(int i)
可以"constant 5"
在被调用时打印,print(5)
但"non-constant 5"
如果被调用为print(i)
where,i
则是一些非常量变量.特别是,在"is constant"分支中,我应该能够将其i
视为constexpr,包括将其用于模板参数等.
宏技巧,模板元编程和SFINAE技巧都可以.理想情况下它是可移植的,但是编译器特定的解决方案总比没有好.
如果存在"错误否定"则可以 - 即,如果常量值有时被检测为非常数(例如,禁用某些优化时).
如果解决方案可以检测到常量值何时间接传递给函数(例如,当一个常量值传递给调用的中间函数print
并且随后内联将常量暴露给print
)时,可以获得奖励积分.最后一种行为显然取决于优化.
如果它自然延伸到多个参数,则可获得双倍奖励
如果一个人可以使用和不带constexpr
参数重载函数的版本,这可能是直截了当的,但你不能.
1我在这里引用"函数参数",因为解决方案并不严格要求在函数内(或在具有特殊参数的调用者/被调用者边界)检测此状态 - 它只需要像函数一样出现给调用者但是可以使用宏或其他技巧,如静态对象operator()
等.
我正在使用gcc 4.6.1并且正在获得一些涉及调用constexpr
函数的有趣行为.这个程序运行得很好,直接打印出来12200160415121876738
.
#include <iostream>
extern const unsigned long joe;
constexpr unsigned long fib(unsigned long int x)
{
return (x <= 1) ? 1 : (fib(x - 1) + fib(x - 2));
}
const unsigned long joe = fib(92);
int main()
{
::std::cout << "Here I am!\n";
::std::cout << joe << '\n';
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这个程序需要永远运行,我从来没有耐心等待它打印出一个值:
#include <iostream>
constexpr unsigned long fib(unsigned long int x)
{
return (x <= 1) ? 1 : (fib(x - 1) + …
Run Code Online (Sandbox Code Playgroud) 为什么不编译:作为返回类型
会出现问题string
吗?
constexpr std::string fnc()
{
return std::string("Yaba");
}
Run Code Online (Sandbox Code Playgroud) 我想实现my_static_assert
与c ++ 17单参数稍有不同的方法static_assert
:如果在编译时my_static_assert
不知道里面的条件,则应该通过。
my_static_assert
以下示例中的第二个应该通过,但是如果我使用static_assert
它将会失败。
#include <iostream>
int x, y;
constexpr int f1() { return 0; }
constexpr int f2() { return 0; }
int f3() { return x; }
int f4() { return y; }
constexpr int sum(int a, int b) { return a + b; }
int main() {
std::cin >> x >> y;
// it should fail
my_static_assert(sum(sum(f1(), f2()), sum(f1(), f1())) != 0);
// it should …
Run Code Online (Sandbox Code Playgroud) 大多数C++编译器都支持SIMD(SSE/AVX)指令
_mm_cmpeq_epi32
Run Code Online (Sandbox Code Playgroud)
我的问题是这个函数没有标记为constexpr
,虽然"语义上"没有理由不使用这个函数,constexpr
因为它是一个纯函数.
有什么办法,我可以写我自己的版本(例如)_mm_cmpeq_epi32
是constexpr
?
显然我希望运行时的函数使用正确的asm,我知道我可以重新实现具有慢速函数的任何SIMD函数constexpr
.
如果你想知道为什么我关心constexpr
SIMD功能.非constexprness具有传染性,这意味着我的任何使用SIMD功能的功能都不可能constexpr
.
[expr.unary.noexcept]的措辞在C++17 中发生了变化。
以前(n4140, 5.3.7 noexcept operator [expr.unary.noexcept]),我的重点是:
- 如果在潜在求值的上下文中表达式将包含,则 noexcept 运算符的结果为 false
(3.1) 对不具有非抛出异常规范 ([except.spec]) 的函数、成员函数、函数指针或成员函数指针的潜在求值调用,除非调用是常量表达式 ([ expr.const]) ...
现在1(7.6.2.6 noexcept 运算符 [expr.unary.noexcept]):
- 除非表达式可能抛出异常 ([except.spec]),否则noexcept 运算符的结果为真。
- 如果函数声明没有 noexcept 说明符,则该声明具有潜在的抛出异常说明,除非...
但是14.5(3)的除非列表未列出constexpr
,因此可能会抛出...
1 LF 在评论中添加的指向 C++17 n4659的链接。
constexpr int f(int i) { return i; }
std::cout << boolalpha << noexcept(f(7)) << std::endl;
int a = 7;
std::cout …
Run Code Online (Sandbox Code Playgroud) constexpr void X() {
/* code, that can be executed at compiletime */
}
void X() {
/* code, that does the same as above, but is optimized for runtime, eg.
including caching, assembler code, ... to optimize runtime performance */
}
Run Code Online (Sandbox Code Playgroud)
如上所示,我想要两个函数,它们基本上都在做相同的事情,一个针对运行时进行了优化,一个针对编译时进行了优化。在我的示例中,运行时版本涉及缓存,这不能在constexpr中完成,但可以提高运行时的性能。
可以通过某种方式(使用C ++ 14)实现吗?
如果只能使用特定于编译器的解决方案来实现此目的,那么它们也可以,但是我更喜欢一种标准解决方案(当前,我不知道有一个解决方案)
c++ ×12
constexpr ×11
c++11 ×6
c++14 ×3
c++17 ×2
optimization ×2
compile-time ×1
g++ ×1
inline ×1
intrinsics ×1
noexcept ×1
simd ×1
sse ×1
templates ×1