For example:
class example{
public:
template <class T> static constexpr T var = T(1.5);
};
int main(){
int a = example::var<int>;
example obj;
int b = obj.var<int>;
return 0;
}
GCC produces error for both:
'example::var<T>' is not a function template
and 'var' is not a member template function
Clang compiles correctly the first one but produces an error for the second: cannot refer to member 'var' in 'example' with '.'
According to the C++14 Standard (ISO/IEC 14882:2014):
Section 14, Paragraph 1.
A variable template at class scope is a static data member template.
Section 9.4, Paragraph 2.
A static member s of class X may be referred to using the qualified-id expression X::s; it is not necessary to use the class member access syntax (5.2.5) to refer to a static member. A static member may be referred to using the class member access syntax, in which case the object expression is evaluated.
Therefore, IMHO, a Variable Template at Class scope (i.e., a Static Data Member Template) could be referred to in both ways. Could it be a bug in the compilers?
The only thing I found to try to justify this behaviour is this sentence in Section 9.4.2, Paragraph 1:
A static data member is not part of the subobjects of a class.
However, the two aforementioned paragraphs are still valid. Besides, I tried the same example referring to other static members such as a variable, a function and a function template, and all of them compile successfully in both GCC and Clang.
class example{
public:
static int constexpr variable = 1;
void static function(){ return; }
template <class T> void static function_template(){ return; }
};
int main(){
example obj;
int a = obj.variable;
int b = example::variable;
obj.function();
example::function();
obj.function_template<int>();
example::function_template<int>();
return 0;
}
Thanks in Advance.
Note 1: compiler versions are clang 3.7.0 and gcc 5.2.1.
Note 2: the keyword static
is required: Variable template at class scope
Note 3: since I want to initialize the variable template, the keyword constexpr
is also required because in my actual code I will instantiate it with float, double and long double (see C++14 Standard (ISO/IEC 14882:2014), Section 9.4.2, Paragraph 3).
Note 4: actual "definitions" of these static data members outside the class (i.e., template <class T> constexpr T example::var;
) are not needed in this example cases. I also tried though, but it makes no difference.
I copied your first code into Visual Studio 2015 (it compiled successfully). I added a few outputs via
std::cout
, where I found usingb
gives a compiler error:uninitialized local variable 'b' used
.a
on the other hand, was successfully printed whenb
was not used. So it would seem c++ is a bit finicky about accessing template static members as you said, requiring you to reference it by its complete, qualified name.Perhaps more curious, are the following lines:
The above line works as expected, outputting
1.5
truncated to1
and an'a'
with a new line. Nothing to write home about.Now here's where it gets interesting... Not only does the above line not print out a value for
obj.var<int>
, the'b'\n
never gets printed either. I even tested against thestd::cout
'sgood()
fail()
andbad()
functions, none of which reported that anything was wrong (and further uses ofstd::cout
were executed successfully outputted).Another oddity I found was that
auto x = obj.var
is legal, and come to find, x is of typeexample
. Now, doing this with a global template variable results in a compiler error (as I expected the first one to as well):Additionally, I found that access
var
through another template static function was successful, further implying that member selection just doesn't work in this caseNow, as far as the standard goes, I'm inclined to believe their phrasing is just a bit ... pedantic. The sections you've quoted from the standard:
and
would seem to imply that this would work. I believe the point where these quotes don't apply in this case is the technicality that a template (of anything) doesn't really "exist" until it is instantiated in a compilation unit (i.e. why the code for templates is often included in the header file itself).
Because of this, although the template variable can be a member of a class, its instantiations aren't ... for some reason ... and therefore require the scope resolution operator as opposed to the member selection operator.
But IMO, accessing static data via the member selection operator is bad practice, as static data and functions are not actually part of a given object. Accessing static data the same way as non-static data can cause relatively-innocent looking code to actually be flawed logic. For instance if for some reason you had a non-const static member called
something
, you could writeexample_object.something = 42
, not expecting anything to change for all other instantiations of that class throughout your program (the same issues as global variables, really). Because of this (and the fact that member access syntax apparently doesn't work for template static member variables anyway), I recommend always using scope resolution to access/modify static content from outside of the class.example_class::something = 42
is a lot more clear that we're changingsomething
for all instances ofexample_class
. In fact, some more-modern languages like C# require you to access static data via the class name unless you're inside said class.Given that several compilers are erroring for different parts of this little example program, I'd be willing to bet it's not covered very well in the standard (and probably not used very often in practice), and the compilers just handle it differently (another reason to avoid it).
tl;dr
Apparently while member selection syntax works for static member variables, it doesn't work for template static member variables (though the compiler doesn't seem to complain). However, the scope resolution syntax does work, and IMO should be preferred anyway.