关于指针值的混淆是编译时constatns

Lin*_*gxi 6 c++ templates pointers compile-time-constant constexpr

在C++中,指针值可能是编译时常量.这是正确的,否则,非类型模板参数constexpr将无法使用指针.但是,据我所知,静态存储的函数和对象的地址(至少)在链接时而不是编译时是已知的.以下是一个例子:

main.cpp中

#include <iostream>

template <int* p>
void f() { std::cout << p << '\n'; }

extern int a;

int main() {
    f<&a>();
}
Run Code Online (Sandbox Code Playgroud)

a.cpp

int a = 0;
Run Code Online (Sandbox Code Playgroud)

我只是想a知道在编译时如何知道地址main.cpp.我希望有人可以向我解释一下.

特别要考虑这一点

template <int* p, int* pp>
constexpr std::size_t f() { 
  return (p + 1) == (pp + 7) ? 5 : 10; 
}

int main() {
    int arr[f<&a, &b>()] = {};
}
Run Code Online (Sandbox Code Playgroud)

应该如何arr分配存储空间?

PLUS:这种机制似乎相当强大.即使我启用了随机基址,也可以获得正确的输出.

Mat*_*Mat 4

编译器不需要知道编译时的&a,就像不需要知道函数地址的值一样。

可以这样想:编译器将实例化您的函数模板作为&a参数并生成“目标代码”(以它用来传递给链接器的任何格式)。目标代码看起来像(好吧,它不会,但你明白了):

func f__<funky_mangled_name_to_say_this_is_f_for_&a>__:
   reg0 <- /* linker, pls put &std::cout here */
   reg1 <- /* hey linker, stuff &a in there ok? */
   call std::basic_stream::operator<<(int*) /* linker, fun addr please? */
   [...]
Run Code Online (Sandbox Code Playgroud)

如果实例化f<b&>,假设b是另一个全局静态,编译器会执行相同的操作:

func f__<funky_mangled_name_to_say_this_is_f_for_&b>__:
   reg0 <- /* linker, pls put &std::cout here */
   reg1 <- /* hey linker, stuff &b in there ok? */
   call std::basic_stream::operator<<(int*) /* linker, fun addr please? */
   [...]
Run Code Online (Sandbox Code Playgroud)

当您的代码需要调用其中任何一个时:

fun foo:
   call f__<funky_mangled_name_to_say_this_is_f_for_&a>__ 
   call f__<funky_mangled_name_to_say_this_is_f_for_&b>__
Run Code Online (Sandbox Code Playgroud)

要调用的确切函数被编码在损坏的函数名称中。生成的代码不依赖于&a或的运行时值&b。编译器知道在运行时会有这样的事情(你告诉它的),这就是它所需要的。它会让链接器填补空白(或者如果你未能兑现你的承诺,就会对你大喊大叫)。


对于您的补充,我担心我对 constexpr 规则不够熟悉,但是我的两个编译器告诉我这个函数将在运行时评估,根据他们的说法,这使得代码不合格。(如果他们错了,那么上面的答案至少是不完整的。)

template <int* p, int* pp>
constexpr std::size_t f() { 
  return (p + 1) == (pp + 7) ? 5 : 10; 
}

int main() {
    int arr[f<&a, &b>()] = {};
}
Run Code Online (Sandbox Code Playgroud)

C++14 标准符合模式下的 clang 3.5:

$ clang++ -std=c++14 -stdlib=libc++ t.cpp -pedantic
t.cpp:10:10: warning: variable length arrays are a C99 feature [-Wvla-extension]
  int arr[f<&a, &b>()];
         ^
1 warning generated.
Run Code Online (Sandbox Code Playgroud)

GCC g++ 5.1,相同模式:

$ g++ -std=c++14 t.cpp -O3 -pedantic
t.cpp: In function 'int main()':
t.cpp:10:22: warning: ISO C++ forbids variable length array 'arr' [-Wvla]
   int arr[f<&a, &b>()];
Run Code Online (Sandbox Code Playgroud)

  • 如果“pp”指向单个整数,@Lingxi 和 Mat“pp+7”是未定义行为。未定义行为可能不会发生在常量表达式内(使用 `constexpr auto x = f&lt;&amp;a, &amp;b&gt;();` 以便从 clang 进行更好的诊断)。另一方面,由于当前对非类型模板参数的限制,您可能无法将数组的元素传递给指针类型的非类型模板参数(这些限制可能是为了防止这些更复杂的情况)。 (2认同)