是否有可能根据C++ 11中的C++ 11表达式是否为常量表达式(即constexpr
)生成编译时布尔值?关于SO的几个问题与此有关,但我在任何地方都没有看到直接答案.
我想在编译时使用类型的名称.例如,假设我写了:
constexpr size_t my_strlen(const char* s)
{
const char* cp = s;
while(*cp != '\0') { cp++; };
return cp - s;
}
Run Code Online (Sandbox Code Playgroud)
现在我希望:
template <typename T>
constexpr auto type_name_length = my_strlen(typeid(T).name());
Run Code Online (Sandbox Code Playgroud)
但是,唉,typeid(T).name()
只是const char*
,而不是constexpr ......还有其他一些constexpr方法来获得一个类型的名字吗?
是否可以在过程/函数中获取当前过程/函数的名称作为字符串?我想在编译时会有一些"宏"扩展.
我的情况是这样的:我有很多程序被给予记录,他们都需要从检查记录的有效性开始,因此他们将记录传递给"验证程序".如果记录无效,验证程序(所有程序都是同一个程序)会引发异常,并且我希望异常的消息不包括验证程序的名称,而是包含调用验证程序的函数/过程的名称程序(自然地).
就是,我有
procedure ValidateStruct(const Struct: TMyStruct; const Sender: string);
begin
if <StructIsInvalid> then
raise Exception.Create(Sender + ': Structure is invalid.');
end;
Run Code Online (Sandbox Code Playgroud)
然后
procedure SomeProc1(const Struct: TMyStruct);
begin
ValidateStruct(Struct, 'SomeProc1');
...
end;
...
procedure SomeProcN(const Struct: TMyStruct);
begin
ValidateStruct(Struct, 'SomeProcN');
...
end;
Run Code Online (Sandbox Code Playgroud)
如果我可以写出类似的内容,那么它会更容易出错
procedure SomeProc1(const Struct: TMyStruct);
begin
ValidateStruct(Struct, {$PROCNAME});
...
end;
...
procedure SomeProcN(const Struct: TMyStruct);
begin
ValidateStruct(Struct, {$PROCNAME});
...
end;
Run Code Online (Sandbox Code Playgroud)
然后每次编译器遇到{$ PROCNAME}时,它只是将当前函数/过程的名称替换为"宏"作为字符串文字.
更新
第一种方法的问题在于它容易出错.例如,由于复制粘贴,你很容易弄错:
procedure SomeProc3(const Struct: TMyStruct);
begin
ValidateStruct(Struct, 'SomeProc1');
...
end;
Run Code Online (Sandbox Code Playgroud)
或错别字:
procedure SomeProc3(const Struct: TMyStruct); …
Run Code Online (Sandbox Code Playgroud) 考虑以下类,将内部结构Y
用作类型,例如.在模板中,稍后:
template<int I>
class X{
template<class T1>
struct Y{};
template<class T1, class T2>
struct Y{};
};
Run Code Online (Sandbox Code Playgroud)
现在,这个示例显然不会编译,错误是第二个X<I>::Y
已经定义或者模板参数太多.
我想在没有(额外)部分特化的情况下解决这个问题,因为int I
参数不是唯一的,并且它的位置可以在不同的部分特化中有所不同(我的实际结构看起来更像这样,上面只是为了简化问题),所以我想one class fits every I
解决.
我的第一个想法显然是enable_if
,但这似乎在我身上失败,例如.我仍然得到同样的错误:
// assuming C++11 support, else use boost
#include <type_traits>
template<int I>
class X{
template<class T1, class = std::enable_if<I==1>::type>
struct Y{};
template<class T1, class T2, class = std::enable_if<I==2>::type>
struct Y{};
};
Run Code Online (Sandbox Code Playgroud)
所以,既然enable_if
失败了,我希望还有另一种方法来实现以下编译时检查:
template<int I>
class X{
__include_if(I == 1){
template<class T1>
struct Y{}; …
Run Code Online (Sandbox Code Playgroud) 我仔细阅读了这篇文章.我理解解释的规则,但我想知道在定义一个常量多维数组并使用给定类型的已知值直接初始化时,究竟是什么阻止编译器接受以下语法:
const int multi_arr1[][] = {{1,2,3}, {1,2,3}}; // why not?
const int multi_arr2[][3] = {{1,2,3}, {1,2,3}}; // OK
error: declaration of 'multi_arr1' as multidimensional array must have bounds
for all dimensions except the first
Run Code Online (Sandbox Code Playgroud)
什么阻止编译器向右看并意识到我们正在处理每个"子阵列"的3个元素,或者只有在程序员为每个子阵列传递例如不同数量的元素时才返回错误{1,2,3}, {1,2,3,4}
?
例如,当处理1D char数组时,编译器可以查看右侧的字符串=
,这是有效的:
const char str[] = "Str";
Run Code Online (Sandbox Code Playgroud)
我想了解发生了什么,以便编译器无法推断出数组维度并计算分配大小,因为现在我觉得编译器已经拥有了所需的所有信息.我在这里错过了什么?
template<unsigned int n>
struct Factorial {
enum { value = n * Factorial<n-1>::value};
};
template<>
struct Factorial<0> {
enum {value = 1};
};
int main() {
std::cout << Factorial<5>::value;
std::cout << Factorial<10>::value;
}
Run Code Online (Sandbox Code Playgroud)
上面的程序在编译期间计算阶乘值.我想在编译时打印阶乘值,而不是在运行时使用cout打印.我们怎样才能在编译时打印阶乘值?
我正在使用VS2009.
谢谢!
我经常编写C#代码,必须使用魔术字符串来表达属性名称.每个人都知道魔术弦的问题.它们很难重构,它们没有编译时检查,并且通常会导致难以诊断的问题.然而,C#/ .NET 在整个地方使用它们来表示属性/类/方法名称.
这个问题已持续多年和多年,目前唯一可行的解决方案是使用表达式树,然后在运行时解析属性名称.这使您获得令人满意的编译时检查,但它使代码复杂化(需要Expression类型的参数),并且会产生运行时成本.
有没有人知道是否有一个特性考虑因为C#/ .NET添加编译时反射来克服这个普遍存在的问题?
看起来这将是一个简单的补充,它将是一个非破坏性的变化,它将使许多开发人员受益匪浅.typeof()运算符已经执行了编译时反射的形式,因此看起来运算符nameof()(或类似的东西)将非常互补.
此外,有没有人知道这个功能的任何潜在问题?
谢谢您的帮助.
我在这里找到了一个代码打印1到1000没有循环或条件
有人可以解释编译时间递归是如何工作的,无法在谷歌中找到它
// compile time recursion
template<int N> void f1()
{
f1<N-1>();
cout << N << '\n';
}
template<> void f1<1>()
{
cout << 1 << '\n';
}
int main()
{
f1<1000>();
}
Run Code Online (Sandbox Code Playgroud)
谢谢!
PHP是一种解释型语言,未编译.然而,我遇到了一本书,提到在编译时PHP中发生的事情,PHP手册指出声明一个const发生在编译时.因为PHP没有编译,所以编译时使用的术语与PHP有什么关系?
如果它只是"当脚本被读取并翻译成解释器子程序时",那么术语编译时和运行时之间有什么区别?
当constexpr在C++ 11中引入时,我很兴奋,但遗憾的是我对其有用性做出了乐观的假设.我假设我们可以在任何地方使用constexpr来捕获文字编译时常量或文字编译时常量的任何constexpr结果,包括这样的事情:
constexpr float MyMin(constexpr float a, constexpr float b) { return a<b?a:b; }
Run Code Online (Sandbox Code Playgroud)
因为仅将函数的返回类型限定为constexpr并不将其使用限制为编译时,并且还必须在运行时可调用,所以我认为这将是确保MyMin只能与编译时计算的常量一起使用的一种方法,这将确保编译器永远不会允许它在运行时执行,让我可以编写另一个更加运行时友好的MyMin版本,理想情况下使用相同名称使用_mm_min_ss内在函数,确保编译器不会生成运行时分支码.不幸的是,函数参数不能是constexpr,所以似乎无法做到这一点,除非这样的事情是可能的:
constexpr float MyMin(float a, float b)
{
#if __IS_COMPILE_TIME__
return a<b?a:b;
#else
return _mm_cvtss_f32(_mm_min_ss(_mm_set_ss(a),_mm_set_ss(b)));
#endif
}
Run Code Online (Sandbox Code Playgroud)
我严重怀疑MSVC++有这样的东西,但是我希望GCC或者clang至少有一些东西可以实现它,不管它看起来有多么不优.
当然,我提供的示例非常简单,但是如果你可以运用你的想象力,在很多情况下你可以随意做一些事情,比如在一个你知道只能在编译时执行的函数中广泛使用分支语句,因为如果它在运行时执行,性能会受到影响.
compile-time ×10
c++ ×7
constexpr ×3
c++14 ×2
templates ×2
.net ×1
c ×1
c# ×1
c++11 ×1
c++17 ×1
delphi ×1
magic-string ×1
php ×1
procedure ×1
reflection ×1