I was porting some code from MSVC(without permissive-) to linux and I learned that if you call constructor of a template base class in initializer list of your class you must specify all the template parameters or you get an error. Seems kind of redundant, since if you make a mistake in retyping the template parameters it is a hard error:
error: type 'Base<int, true>' is not a direct or virtual base of 'Derived'
full code here:
template <typename T, bool has_x>
struct Base
{
Base(T t): t_(t){
}
T t_=0;
};
template <typename T>
class Derived : public Base<T, false>
{
public:
// : Base<T, true> is hard error
Derived(const T& t) : Base<T, false>(t) {}
};
int main()
{
Derived d(47);
}
Is there a strong reason for this, or just standardization process never took time to special case this use case?
Template non-type arguments in C++It is also possible to use non-type arguments (basic/derived data types) i.e., in addition to the type argument T, it can also use other arguments such as strings, function names, constant expressions, and built-in data types.
Deriving from a non-template base class There is no requirement that your base class be a template. It is quite possible to have a template class inherit from a 'normal' class. This mechanism is recommended if your template class has a lot of non-template attributes and operations.
What can be passed by non-type template parameters during compile time? Explanation: Non-type template parameters provide the ability to pass a constant expression at compile time. The constant expression may also be an address of a function, object or static class member.
A non-template class can have template member functions, if required. Notice the syntax. Unlike a member function for a template class, a template member function is just like a free template function but scoped to its containing class.
You only need to do that when Derived
is a template and the type of the base depends on its template parameters.
This compiles, for example:
template <typename T>
class Derived : public Base<int, false>
{
public:
Derived(const T& t) : Base(t) {}
};
As far as I know, here (in member initializer list) Base
is actually the injected-class-name of Base<...>
, inherited from it like everything else.
And if the type of the base does depend on the template parameters, its inherited injected-class-name becomes inaccessible (at least directly), just like any other member inherited from it.
For a member variable/function, you'd add this->
to access it, but for a type member you need Derived::
:
template <typename T>
class Derived : public Base<T, false>
{
public:
Derived(const T& t) : Derived::Base(t) {}
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With