如果您在 C++ 中使用一个将整数值作为参数的模板,那么对于用作参数的整数变量是否有任何要求与将变量用作函数调用中的参数不同?
这是对here的后续问题 。我特别想解决函数或模板是否存在声明为“extern const int”的差异 WRT 变量?
我可以看到,对于某些模板案例,编译时需要参数值。这总是正确的吗?有没有办法指定在运行时使用该值,也许仅用于参数值的某些用途?
The following is from the standard.
14.3.2.1:
A template-argument for a non-type, non-template template-parameter shall be one of:
- an integral constant-expression of integral or enumeration type; or
- the name of a non-type template-parameter; or
- the address of an object or function with external linkage, including function templates and function template-ids but excluding non-static class members, expressed as & id-expression where the & is optional if the name refers to a function or array, or if the corresponding template-parameter is a reference; or
- a pointer to member expressed as described in 5.3.1 .
5.19.1:
In several places, C++ requires expressions that evaluate to an integral or enumeration constant: as array bounds (8.3.4, 5.3.4), as case expressions (6.4.2), as bit-field lengths (9.6), as enumerator initializers (7.2), as static member initializers (9.4.2), and as integral or enumeration non-type template arguments (14.3).
constant-expression: conditional-expression
An integral constant-expression can involve only literals (2.13), enumerators, const variables or static data members of integral or enumeration types initialized with constant expressions (8.5), non-type template parameters of integral or enumeration types, and sizeof expressions. Floating literals (2.13.3) can appear only if they are cast to integral or enumeration types. Only type conversions to integral or enumera- tion types can be used. In particular, except in sizeof expressions, functions, class objects, pointers, or references shall not be used, and assignment, increment, decrement, function-call, or comma operators shall not be used.
With respect to your previous post I believe the essence in the part "const variables ... initialised with ..." (and I don't think initialised externally counts).
It has to be a integral constant expression. That's explained by the Standard document at 5.19
:
An integral constant-expression can involve only literals (2.13), enumerators, const variables or static data members of integral or enumeration types initialized with constant expressions (8.5), non-type template parameters of integral or enumeration types, and sizeof expressions. Floating literals (2.13.3) can appear only if they are cast to integral or enumeration types. Only type conversions to integral or enumeration types can be used.
Note that "integral" is another term for "integer", but is not the same as "int". "char" for example has integer/integral type, but is not the int type, obviously. So concretely, the following is allowed
10 or 10L or anything like that
enum { THIS, OR, THAT };
int const this_one = 10;
sizeof(char)
Any of those can be used as a template argument for a parameter that has an integral type of the corresponding type. Some conversions are still applied though. So if it wants an int and you pass a char, it automatically promotes the char to the int. Same if you provide an enumerator and it wants an int.
So by those rules, if you have
extern const int SomeName;
And it does not see a definition which initializes that constant with a integral constant expression, it can't be used as a template argument. But it can be used as a function argument, of course. Those don't need to be known at compile time because those are not part of a type. The moment you name a template specialization, the arguments you used become part of the type:
MyGreatStack<int, 4> // 4 is now part of the type MyGreatStack<int, 4>!
Note that there are other ways to pass SomeName
as an argument. However, all of which can not be accepted by an integer template parameter. You can accept the above by a reference parameter, for example
template<const int& V> struct NowItWorks { };
And it would accept the SomeName
of above. Now, rather than a value, a particular location that is unique across the whole program (as the variable has extern
linkage) has been chosen.
在编译时总是需要 int 的值。
由于每个模板实例化都是一段单独的编译代码(即使对于整数模板参数),整数需要在编译时可用(并且必须保证永远不会更改)。
这也是为什么当您要使用大量唯一值时最好不要使用整数模板参数的原因——您很快就会得到一个巨大的可执行文件。