Zsolt Tomis
Zsolt Tomis

Reputation: 11

Variadic template and default value with inheritance

#include <iostream>

struct A {
    int a;
    std::string b;
    A(int a_, std::string b_) : a(a_), b(b_) { std::cout << a << b << std::endl; }
};

struct B : public A {
    static const int VERSION=2;
    float c;

    template<typename ... ARGS>
    B(float c_, int v=VERSION, ARGS&&... args) : A(v, std::forward<ARGS>(args)...), c(c_) { std::cout << c << std::endl; }
};

int main() {    
    B(3.14, "abc");
}

Hi all, the compiler gives gives me template argument deduction/substitution failed error. How can I use a default value with a variadic template?

variadic.cpp: In function ‘int main()’:
variadic.cpp:18:15: error: no matching function for call to ‘B::B(double, const char [4])’
  B(3.14, "abc");
               ^
variadic.cpp:14:2: note: candidate: template<class ... ARGS> B::B(float, int, ARGS&& ...)
  B(float c_, int v=VERSION, ARGS&&... args) : A(v, std::forward<ARGS>(args)...), c(c_) { std::cout << c << std::endl; }
  ^
variadic.cpp:14:2: note:   template argument deduction/substitution failed:
variadic.cpp:18:15: note:   cannot convert ‘"abc"’ (type ‘const char [4]’) to type ‘int’
  B(3.14, "abc");
               ^
variadic.cpp:9:8: note: candidate: B::B(const B&)
 struct B : public A {
        ^
variadic.cpp:9:8: note:   candidate expects 1 argument, 2 provided
variadic.cpp:9:8: note: candidate: B::B(B&&)
variadic.cpp:9:8: note:   candidate expects 1 argument, 2 provided

Upvotes: 0

Views: 83

Answers (2)

max66
max66

Reputation: 66230

The problem is if a function/method parameter has a default value, all following parameters must have a default value.

So

template<typename ... ARGS>
B(float c_, int v=VERSION, ARGS&&... args) 
   : A(v, std::forward<ARGS>(args)...), c(c_)
 { std::cout << c << std::endl; }

is wrong because there aren't default values for args.

Or better: you can write the following signature

B(float c_, int v=VERSION, ARGS&&... args)

but the default value for v is used only if you pass to the constructor only a value (c_) because args... is empty so v is the last parameter.

But if you want a some args..., the default value for v is ignored because, otherwise, the compiler can't know if a second integer parameter is the not-default value for v or the first args...

Upvotes: 1

MSalters
MSalters

Reputation: 179991

The problem here is that your constructor can be called with one, two or more arguments.

If you call it with one argument, the second argument is defaulted.

If you provide two or more arguments, the provided default argument is not used. Your second argument is used, and it has to match the type of the second parameter.

Note that in general, you can achieve similar results by overloading a function instead of providing default arguments. In this case, I suspect that would give you the results you intend, but that's me guessing at your intents.

Upvotes: 1

Related Questions