mercredi 26 juillet 2017

Template hierarchy constructor arguments

I'm having trouble understanding why my template hierarchy won't pass constructor arguments deeper than one layer.

So far I've read that it may have something to do with namespacing or template constructors being unnamed. My various attempts at getting the constructor arguments through to the base class with scoping directives have failed.

// test.cc
#include <string>

// Base class, obviously.
template <typename T>
class Base {
public:
    Base(const T& t) : _t(t) {}
    virtual ~Base() { }

    virtual T getVal() const { return _t; }

private:
    T _t;
};

// First derivation. This works, although it is explicit.
class DerivedOne : public virtual Base<std::string>
{
public:
    DerivedOne(const std::string& path) : Base<std::string>(path) {}
    virtual ~DerivedOne() {}
};

// Second derivation. Constructor fails to compile unless I explicitly
// pass the 'path' argument to Base in the initializer list or create a
// default constructor for Base (which, of course, leaves Base::_t
// uninitialized).
class DerivedTwo : public virtual DerivedOne
{
public:
    DerivedTwo(const std::string& path) : DerivedOne(path) {}
    // This works
    // DerivedTwo(const std::string& path) : DerivedOne(path), Base(path) {} 
    virtual ~DerivedTwo() {}
};

int main()
{
    return 0;
}

The compiler complains:

test.cc: In constructor ‘DerivedTwo::DerivedTwo(const string&)’:
test.cc:31:58: error: no matching function for call to ‘Base<std::__cxx11::basic_string<char> >::Base()’
     DerivedTwo(const std::string& path) : DerivedOne(path) {}
                                                          ^
test.cc:7:5: note: candidate: Base<T>::Base(const T&) [with T = std::__cxx11::basic_string<char>]
     Base(const T& t) : _t(t) {}
     ^
test.cc:7:5: note:   candidate expects 1 argument, 0 provided
test.cc:5:7: note: candidate: Base<std::__cxx11::basic_string<char> >::Base(const Base<std::__cxx11::basic_string<char> >&)
 class Base {
       ^
test.cc:5:7: note:   candidate expects 1 argument, 0 provided

Why do I need to declare a default constructor when it seems that the parameterized constructor should be called? Why must I explicitly pass DerivedTwo's parameter to Base, since I've passed it to DerivedOne (who should pass it to Base)?

Is there some way to avoid this duplication? Does this mean I can't use initializer lists when a base template constructor parameter is allocated on the heap in a derived class initializer list?

Aucun commentaire:

Enregistrer un commentaire