4

I'm following the example from here, however I am using templates and calling a constructor of one of the derived classes. The following code works without templates but when included I am not sure why I get the following error:

: error: no matching function for call to ‘AbsInit<double>::AbsInit()’
     NotAbsTotal(int x) : AbsInit(x) {};
                                   ^

Here is the code:

#include <iostream>

using namespace std;

template<typename T>
class AbsBase
{
    virtual void init() = 0;
    virtual void work() = 0;
};

template<typename T>
class AbsInit : public virtual AbsBase<T>
{
public:
    int n;
    AbsInit(int x)
    {
        n = x;
    }
    void init() {  }
};

template<typename T>
class AbsWork : public virtual AbsBase<T>
{
    void work() {  }
};

template<typename T>
class NotAbsTotal : public AbsInit<T>, public AbsWork<T>
{
public:
    T y;
    NotAbsTotal(int x) : AbsInit(x) {};
};    // Nothing, both should be defined


int main() {
  NotAbsTotal<double> foo(10);
  cout << foo.n << endl;

}
Community
  • 1
  • 1
pyCthon
  • 11,746
  • 20
  • 73
  • 135
  • @TavianBarnes ahaha thanks! make an answer please – pyCthon Jul 25 '16 at 15:59
  • This should work. But maybe my dupe is wrong as it should have been fixed in GCC 4.5, which massively predates C++14. What is your compiler and version? – Lightness Races in Orbit Jul 25 '16 at 16:06
  • And compilation command. – Lightness Races in Orbit Jul 25 '16 at 16:14
  • `AbsInit` is a dependent base class. `AbsInit` is an injected class name within the scope of `AbsInit` itself, but since the scope of `AbsInit` is not examined, the only `AbsInit` that can be found in the first phase of name lookup is a class template name (when searching the global scope), not a type referring to some specific instantiation of `AbsInit` – Piotr Skotnicki Jul 25 '16 at 16:21
  • @PiotrSkotnicki: `C++11: 14.6.1/3` appears to say the opposite in an example. It's a shame you didn't actually read the potential dupe before re-opening this! – Lightness Races in Orbit Jul 25 '16 at 16:49
  • @LightnessRacesinOrbit nah, it presents an example using a qualified name lookup, here we have unqualified name lookup. it means that you can type `NotAbsTotal(int x) : NotAbsTotal::AbsInit(x)`, but still not `NotAbsTotal(int x) : AbsInit(x)` – Piotr Skotnicki Jul 25 '16 at 16:52

2 Answers2

2

You need to pass a template-argument (in this case, T) to the base template-class.

Change this

template<typename T>
class NotAbsTotal : public AbsInit<T>, public AbsWork<T>
{
public:
    T y;
    NotAbsTotal(int x) : AbsInit<T>(x) // You need to pass the template parameter
    {};
};    
WhiZTiM
  • 21,207
  • 4
  • 43
  • 68
2

In the below snippet...

template<typename T>
class NotAbsTotal : public AbsInit<T>
{
    NotAbsTotal(int x) : AbsInit(x) {}
};

... AbsInit<T> is a dependent base class:

A dependent base class is a base class that is a dependent type and is not the current instantiation.

... and it is attempted to be referred to using an unqualified injected-class-name (AbsInit), but:

The injected-class-name of a class (Clause [class]) is also considered to be a member of that class for the purposes of name hiding and lookup.

... however, [temp.dep]/p3:

In the definition of a class or class template, the scope of a dependent base class ([temp.dep.type]) is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member. [ Example:

typedef double A;
template<class T> class B {
  typedef int A;
};
template<class T> struct X : B<T> {
  A a;              // a has type double
};

[...]

end example ]

As such, AbsInit cannot be bound to an injected-class-name which exists in the scope of AbsInit<T> itself. That name, left alone, is subject to unqualified name lookup, and refers to a class template found in the global namespace.

To avoid the error or enforce desired name resolution, append a template argument list to the class template name AbsInit:

NotAbsTotal(int x) : AbsInit<T>(x) {}
//                          ~~^

or use a qualified name:

NotAbsTotal(int x) : NotAbsTotal::AbsInit(x) {}
//                   ~~~~~~~~~~^

Remark: once the base class is not dependent (i.e., a concrete type is used, e.g., AbsInit<int>), you can use the unqualified form of the injected-class-name.

Community
  • 1
  • 1
Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160