Bee*_*ope 12 c++ optimization constexpr c++11
我可以在编译时检测"函数参数" 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()等.
为了检测constexpr适用性,人们可以考虑来自 @JohannesSchaub-litb 的GCC-only 建议(有关限制,请参阅链接的答案):
template<typename T>
constexpr typename remove_reference<T>::type makeprval(T && t) {
return t;
}
Run Code Online (Sandbox Code Playgroud)
不同情况下的工作示例如下
#include <iostream>
////////////////////////////////////////////////////////////////////////////////
// /sf/answers/931355071/
template<class T>
constexpr std::remove_reference_t<T> makeprval(T&& t) {
return t;
}
#define isprvalconstexpr(e) noexcept(makeprval(e))
////////////////////////////////////////////////////////////////////////////////
template<bool is_constexpr, class Lambda>
struct HybridArg {
using T = std::invoke_result_t<Lambda>;
Lambda lambda_;
constexpr operator T() const { return lambda_(); }// implicit conversion
};
template<bool is_constexpr, class Lambda>
constexpr auto make_hybrid_arg(Lambda lambda) {
return HybridArg<is_constexpr, Lambda>{lambda};
}
#define WRAP_ARG(arg) \
make_hybrid_arg<isprvalconstexpr(arg)>( \
[&] { return arg; } \
) \
////////////////////////////////////////////////////////////////////////////////
template<int i>
void print_impl_constexpr() {
std::cout << i << ": ";
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void print_impl_fallback(int i) {
std::cout << i << ": ";
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
////////////////////////////////////////////////////////////////////////////////
// option 1 (for choosing implementation):
// compile-time introspection
template<class Arg>
struct is_constexpr_arg : std::false_type {};
template<class Lambda>
struct is_constexpr_arg<
HybridArg<true, Lambda>
> : std::true_type {};
template<class Arg>
void print_by_introspection(Arg arg) {
if constexpr(is_constexpr_arg<Arg>{}) {
print_impl_constexpr<arg>();
}
else {
print_impl_fallback(arg);
}
}
////////////////////////////////////////////////////////////////////////////////
// option 2 (for choosing implementation):
// overload
void print_by_overload(int arg) {
print_impl_fallback(arg);
}
template<class Lambda>
void print_by_overload(HybridArg<true, Lambda> arg) {
print_impl_constexpr<arg>();
}
////////////////////////////////////////////////////////////////////////////////
template<class Arg>
void indirection(Arg arg) {
print_by_introspection(arg);
print_by_overload(arg);
}
void bad_indirection(int arg) {
print_by_introspection(arg);
print_by_overload(arg);
}
////////////////////////////////////////////////////////////////////////////////
int main() {
{
int i = 0;
indirection(i);
}
{
int i = 1;
indirection(WRAP_ARG(i));
}
{
constexpr int i = 2;
indirection(WRAP_ARG(i));
}
{
constexpr int i = 3;
bad_indirection(WRAP_ARG(i));
}
}
Run Code Online (Sandbox Code Playgroud)
使用GCC编译后的输出:
0: void print_impl_fallback(int)
0: void print_impl_fallback(int)
1: void print_impl_fallback(int)
1: void print_impl_fallback(int)
2: void print_impl_constexpr() [with int i = 2]
2: void print_impl_constexpr() [with int i = 2]
3: void print_impl_fallback(int)
3: void print_impl_fallback(int)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
885 次 |
| 最近记录: |