C ++ idioms when declaring class members and constructors

Although both of the following compilations (since Visual Studio 2013), are they more "correct" with respect to C ++ idioms? In particular, I am talking about explicit template parameters when calling base class constructors and declaring members. Does the Standard have an idea about this? Is there any good practical reason to prefer each other?

template<class T> class Bar1 : public Base<T> { public: Bar1() : Base() {} Bar1(T value) : Base(value) {} Bar1(Bar1 const & other) : Base(other.value) {} void Foo(Bar1 const & other) { // Some foo related activity. } }; template<class T> class Bar2 : public Base<T> { public: Bar2() : Base<T>() {} Bar2(T value) : Base<T>(value) {} Bar2(Bar2<T> const & other) : Base<T>(other.value) {} void Foo(Bar2<T> const & other) { // Some foo related activity. } }; 
+6
source share
2 answers

This question depends on what is called injected-class-name. From the class]

The class name is inserted into the area in which it is declared immediately after viewing the class name. The class name is also inserted into the scope of the class itself; this is known as the name of the introduced class. To verify access, the name of the entered class is considered as the name of the public member.

And from [temp.local]:

Like regular (non-template) classes, class templates have a name with the class introduced (section 9). The name of the entered class can be used as a template name or type name. When used with a list argument template, as a template argument for a template template, or as the ending identifier in a specifier of a specified type declaration of a friend’s class template, it refers to the class template itself. Otherwise, it is equivalent to the template name, followed by the template parameters of the class template enclosed in <> .

That is, in the definitions of Bar1<T> or Bar2<T> you can use Bar1 or Bar2 to indicate the full type of the class. That is, these declarations are equivalent:

 void Foo(Bar2<T> const & other); void Foo(Bar2 const & other); 

However, the search rules apply as usual. Although Base has the name of the entered class, it is a dependent name and therefore cannot be found using normal unqualified searches. From [temp.dep]:

In the definition of a class template or class, the domain of the dependent base class (14.6.2.1) is not considered during the search for an unqualified name, either at the definition point of a class template or member, or during the creation of a template or class member.

what does it do:

 Bar1() : Base() {} 

poorly educated. Base is an unqualified search, and there is no such name Base . There is Base<T>::Base (there is the name of the entered class), but this area has not been studied. You will have to either perform a qualified search:

 Bar1() : Bar1<T>::Base() {} Bar1() : Bar1::Base() { } 

or not rely on the name of the entered Base class:

 Bar1() : Base<T>() { } 

VS mistakenly accepts Bar1 . Bar2 excellent if in more detail than possible. There is nothing wrong.

It is also worth noting that if the base was not dependent, you could still use its injected class name, even if it was a template:

 template <class T> struct Base { }; struct Derived : Base<int> { Derived() : Base() { } // OK, lookup finds Base<int>::Base }; 
+2
source

The first form is incorrect and should not be compiled. To understand why, consider what happens if you inherit from Base<Foo> and Base<Bar> (or Base<T> and Base<Base<T>> or something else). How can ambiguity be eliminated?

The idea that the first form will work can be obtained from the erroneous application of the rule, which in the definition of the class template you do not need to provide template parameters when mentioning the class name. However, this does not apply to the base class template.

0
source

All Articles