c++templatesusing-declaration

Default argument for template not working


I have a chain of nested templated using declarations. It looks something like this:

template <typename A, typename B, typename C, typename D>
class Foo {
public:
    Foo() : value{0} {};

    template <typename AC, typename BC, typename CC, typename DC>
    Foo(const Foo<AC, BC, CC, DC>& rhs) : value{rhs.value} {}

    template <typename AC, typename BC, typename CC, typename DC>
    Foo& operator=(const Foo<AC, BC, CC, DC>& rhs) {
        value = rhs.value;
        return *this;
    }

    template <typename F>
    F convertTo() {
        return F(*this);
    }

    C value;
};

template <typename ThingC, typename ThingD>
using Bar = Foo<int, float, ThingC, ThingD>;

template <typename ThingD = long double>
using Bif = Bar<char, ThingD>;

The following gives me trouble:

int main(int argc, char* argv[]) {
    Bif bifDefault;
    Bif<long> bifLong;

    Bif<unsigned> bifUnsigned = bifDefault.convertTo<Bif<unsigned>>();
    Bif<long double> bifLongDouble = bifLong.convertTo<Bif>(); // ERROR...
    // expected a type, got 'Bif'
}

I also get an error at the F convertTo line : template argument deduction/substitution failed.

And the weirdest error, at the ERROR line:

no instance of function template "Foo<A, B, C, D>::convertTo [ with A=int, B=float, C=char, D=long int]" matches the argument list

D=long int! What's going on here? Changing it to just double doesn't work either. Clearly, the default template argument is propagating through to the function, but it's doing it wrong for long double, and doesn't work even when it does get the type correct.

How do I get this to work?


Solution

  • The issue is that Bif isn't a type, it's a templated type. You're getting away with it when you declare bifDefault because of CTAD, but it doesn't apply when you call convertTo (you're not passing a non-type template parameter). The code compiles as expected when replaced with bifLong.convertTo<Bif<>>().