23

When answering this SO question, I found in the Standard (already C++03, still in C++11) that you can only use addresses as non-type template arguments if they're of the form & id-expression (plus some exceptions).

But I couldn't answer why this is the case.

14.3.2 Template non-type arguments [temp.arg.nontype]

A template-argument for a non-type, non-template template-parameter shall be one of:

[...]

— a constant expression (5.19) that designates the address of an object with static storage > duration and external or internal linkage or a function with external or internal linkage, including function templates and function template-ids but excluding non-static class members, expressed (ignoring parentheses) as & id-expression, except that the & may be omitted if the name refers to a function or array and shall be omitted if the corresponding template-parameter is a reference; [...]

(n3485, emphasis mine)

Example:

using TFoobar = int (*)();
template < TFoobar tp > struct foo_struct{};

int foobar() { return 42; }
constexpr TFoobar pFoobar = &foobar;

foo_struct < &foobar > o0; // fine
foo_struct < pFoobar > o1; // ill-formed

I guess it has something to do with the translation phases, namely the compiler doesn't know much about addresses. Yet, why isn't it allowed? Shouldn't it be possible for the compiler to use something similar to macro substitution to replace pFoobar with &foobar?

Community
  • 1
  • 1
dyp
  • 38,334
  • 13
  • 112
  • 177
  • 1
    I'd guess it is a matter of making conservative changes. C++11 is full of really strict ways for the language to do things in order to make things easier for the compiler implementers. It might be possible to extend C++11 to allow for the above, but that is a matter for C++14 or beyond! – Yakk - Adam Nevraumont Apr 08 '13 at 17:40
  • [There's a proposal](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4268.html) to remove these restrictions. – dyp Jan 01 '15 at 21:14
  • Lifting this restriction will greatly improve the implementation of "delegates". Right now, if a we use a member fn as template param, there seems to be no way to "generate" or even "forward" this param via helper class! The user must type the expression one way or another. – user362515 Mar 23 '15 at 10:41

2 Answers2

2

Consider classes Foo<&X> and Foo<&Y>, both with a static member int Bar. The linker must be able to tell whether your program has 1 or 2 Bar objects. Now consider that the linker is also the party most likely responsible for assigning values to &X and &Y.

Look at the Standard again. As it's written, the compiler doesn't need to communicate the actual address to the linker. Instead, it passes the id-expression. Linkers are already quite capable of determining whether two id-expression's are the same, even before assigning a numerical address to them.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • 1
    I'm aware that a substitute can be used instead of the actual address. But how does that answer my question why a `constexpr` object cannot be used as a pointer template argument? – dyp Apr 09 '13 at 19:56
  • And, to add to DyP comment, if a constexpr pointer to function is made, its value can be computed and passed to the linker (either `&id` or `nullptr`) (and more: this does not contradict your answer). – Synxis Apr 09 '13 at 21:36
  • @Synxis: No, the compiler cannot compute the value of a (constexpr) pointer to function, since the linker will give the function its address. – MSalters Apr 10 '13 at 15:19
  • @DyP: `constexpr` tells the compiler that it must calculate the value at compile time, so that its value can be used at compile time too. But in this case, the compile cannot calculate its value, since that address is assigned only later by the linker. – MSalters Apr 10 '13 at 15:27
  • 3
    @MSalters Actually, AFAIK, `constexpr` does _not_ tell the compiler it _must_ compute the value at compile time (if you like, I can look up the paragraphs of the Std), it's much more subtle. If you can use a function ptr to instantiate a template, it must have a fixed "value" at compile time, although it doesn't have to be the address as you said. So why can't you use this fixed value indirectly via the function ptr? AFAIK, the compiler could just replace the `constexpr` pointer with the expression the pointer has been initialized with (and recur until it's an `& id-expression`). – dyp Apr 10 '13 at 16:40
  • +1 for DyP, that was what I meant with the 'computed value'. The value of the function pointer, even constexpr, could be `"&id-expression"` (as a string), ie not an actual address, but an id for the linker, like the ones passed using 'normal' function pointers. – Synxis Apr 10 '13 at 16:45
0
  1. It cannot be a variable, since variables are only set at runtime.
  2. It cannot be a constexpr, since the value of an address cannot be known at compile time; in most cases it will only be fixed after relocation prior to execution.
  3. It might theoretically be an arithmetic expression (even though it isn't allowed in the standard), but in the common case of an address of an array element, you can simply use &arr[i] instead of arr + i.
MvG
  • 57,380
  • 22
  • 148
  • 276
  • What cannot be a constexpr ? A function address is known at compile-time (including link-time). Furthermore, relocation mainly occurs for shared libraries, on modern systems `exe` are often not relocated. – Synxis Apr 09 '13 at 21:32
  • Ad 3: A constant expression _is_ allowed in the Standard if I interpret it correctly; it's just forbidden for functions (function ptrs). Though I can see why an arithmetic expression doesn't make much sense on a function ptr, a constant expression evaluating to a function ptr does make sense to me, see the example in my OP (or Synxis original question). – dyp Apr 11 '13 at 11:24