C++ “我可以在编译时检测到吗?”;函数参数";它们是编译时常量
我是否可以在编译时检测“函数参数”1是否为编译时常量 例如,一个函数C++ “我可以在编译时检测到吗?”;函数参数";它们是编译时常量,c++,c++11,optimization,constexpr,C++,C++11,Optimization,Constexpr,我是否可以在编译时检测“函数参数”1是否为编译时常量 例如,一个函数print(int i),如果被称为print(5),它可以打印“常量5”,但是如果被称为print(i),它可以打印i是一些非常量变量。特别是,在“is constant”分支中,我应该能够将I视为constepr,包括将其用于模板参数等 宏技巧、模板元编程和SFINAE技巧都可以。理想情况下,它是可移植的,但是特定于编译器的解决方案总比没有好 如果存在“错误否定”,也就是说,如果常量值有时被检测为非常量(例如,当某些优化被禁
print(int i)
,如果被称为print(5)
,它可以打印“常量5”
,但是如果被称为print(i)
,它可以打印i
是一些非常量变量。特别是,在“is constant”分支中,我应该能够将I
视为constepr,包括将其用于模板参数等
宏技巧、模板元编程和SFINAE技巧都可以。理想情况下,它是可移植的,但是特定于编译器的解决方案总比没有好
如果存在“错误否定”,也就是说,如果常量值有时被检测为非常量(例如,当某些优化被禁用时),这是可以的
如果解决方案能够检测何时将常量值间接传递给函数(例如,何时将常量值传递给调用print
的中间函数,该函数随后内联,将常量公开给print
),则会获得额外的积分。最后一种行为显然依赖于优化
如果它自然地扩展到多个参数,则会获得双倍的加分
如果可以有带和不带constexpr
参数的重载函数版本,这可能很简单,但是
1我在这里引用“函数参数”,因为解决方案并不严格要求在函数中检测此状态(或在具有特殊参数的调用方/被调用方边界处)——它只需在调用方看来像函数,但宏或其他技巧,如带有
操作符()的静态对象< /P> >可使用。 < P>检测<代码> CONTXPRP</代码>适用性时,可考虑此<强> GCC仅< <强>(参见限制性链接答案):
它不一定是一个普通的函数void print(int i)-它可以是一个类似函数的宏,对其参数执行一些魔术,并根据它是常数还是模板魔术调用不同的函数
你说的“像宏一样的功能”
嗯。。。首先,我必须警告你,像宏这样的C风格函数是危险的。邪恶,伊姆霍
这么说来,如果您真的接受基于宏的解决方案,我想将它与constepr
方法、模板struct
、static
局部变量和SFINAE组合在一起
如果定义以下模板PrintStruct
struct
template <typename T>
struct PrintStruct
{
template <bool>
static void func (...)
{ std::cout << "func non-const: " << T::func(true) << std::endl; }
template <bool b, int I = T::func(b)>
static void func (int)
{ std::cout << "func const: " << I << std::endl; }
};
请注意,在常量版本的PrintStruct::func()
中,打印的值是一个模板整数值;so还可用于模板参数、C样式数组维度、static\u assert()
s测试等
我不确定这是否是一个完美的标准(我不是一个真正的专家),并且它可以满足您的需求,但是下面是一个完整的工作示例
#include <iostream>
template <typename T>
struct PrintStruct
{
template <bool>
static void func (...)
{ std::cout << "func non-const: " << T::func(true) << std::endl; }
template <bool b, int I = T::func(b)>
static void func (int)
{ std::cout << "func const: " << I << std::endl; }
};
#define Print(i) \
[&]() \
{ \
static int const printLocalVar { i }; \
\
struct local_foo \
{ \
static constexpr int func (bool b) \
{ return b ? printLocalVar : 0; } \
} ; \
\
PrintStruct<local_foo>::func<true>(0); \
} \
()
int main()
{
constexpr int i { 2 };
int const j { 3 };
int k { 4 };
int const l { k+1 };
Print(1); // print func const: 1
Print(i); // print func const: 2
Print(j); // print func const: 3
Print(k); // print func non-const: 4
Print(l); // print func non-const: 5
Print(2+2); // print func const: 4
}
#包括
模板
结构打印结构
{
模板
静态void func(…)
{std::我记得GCC有类似于\uuuu内置常量\uu p
的东西。然而,对于宏,我确信有更多的可移植方式,但该宏肯定必须面向用户。constexpr可以按照以下方式检测:也许这会有帮助?顺便说一句,你说“简单”用constexpr参数重载,但事实并非如此。当建议标准化时,这引发了巨大的讨论。@max66-对,但它不一定是一个普通函数void print(int i)
-它可能是一个类似于宏的函数,对其参数执行一些魔法,并根据它是否是常数调用不同的函数,也可能是一个模板魔法。我的意思是代码的用户应该编写类似于打印(5)的东西
在内部,我希望能够采用constexpr
代码路径,这取决于参数是否可以用作constexpr。您可以使用参数计数宏技巧的变体将宏解决方案扩展到多个参数(请参阅:),因此您可以定义Print1
,Print2
,…等,然后Print(…)
将根据参数计数宏的结果调用右侧的PrintN
宏。将宏的语句块用do
和while(0)包围
以便宏将扩展为语句。这避免了else
的语法问题,例如if(cond)Print(x);else{some;other;stuff;}这是C语言中的宏。对于C++,我想你可以尝试将你的块转换成一个直接调用的lambda,这会给你一个表达式。@ jxh -我已经和C(很多年前)工作了很多年。但我不记得这个把戏了;关于lambda……嗯,我看不出有什么办法可以做到这一点;但也许我错了……今天我没有时间,但也许明天,我会试试。如果你成功地将我的宏转换为lambda,请写下它作为答案。我对其他类型的问题感兴趣。@BeeOnRope-正确:不适用于表达式;aboutval##i
是为了避免使用与本地静态变量相同的名称调用pass变量到Print
;但是考虑到这会阻止使用表达式,我认为这是一个坏主意,最好为本地变量修复一个长而奇怪的名称。@BeeOnRope-macro修改为接受expressions(但不要使用包含printLocalVar
:()的表达式调用它,除非我遗漏了什么,否则这需要调用方显式标记每个参数是否为常量。如果您愿意施加该限制,似乎有许多可能的解决方案-例如,只需调用print()
而不是打印(5)
用于常量参数(至少用于类型
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)
template <typename T>
struct PrintStruct
{
template <bool>
static void func (...)
{ std::cout << "func non-const: " << T::func(true) << std::endl; }
template <bool b, int I = T::func(b)>
static void func (int)
{ std::cout << "func const: " << I << std::endl; }
};
#define Print(i) \
[&]() \
{ \
static int const printLocalVar { i }; \
\
struct local_foo \
{ \
static constexpr int func (bool b) \
{ return b ? printLocalVar : 0; } \
} ; \
\
PrintStruct<local_foo>::func<true>(0); \
} \
()
#include <iostream>
template <typename T>
struct PrintStruct
{
template <bool>
static void func (...)
{ std::cout << "func non-const: " << T::func(true) << std::endl; }
template <bool b, int I = T::func(b)>
static void func (int)
{ std::cout << "func const: " << I << std::endl; }
};
#define Print(i) \
[&]() \
{ \
static int const printLocalVar { i }; \
\
struct local_foo \
{ \
static constexpr int func (bool b) \
{ return b ? printLocalVar : 0; } \
} ; \
\
PrintStruct<local_foo>::func<true>(0); \
} \
()
int main()
{
constexpr int i { 2 };
int const j { 3 };
int k { 4 };
int const l { k+1 };
Print(1); // print func const: 1
Print(i); // print func const: 2
Print(j); // print func const: 3
Print(k); // print func non-const: 4
Print(l); // print func non-const: 5
Print(2+2); // print func const: 4
}