7

Compiling this:

#include <iostream>
#include <memory>

template <auto val = 42>
struct A
{
    A()
    {
        std::cerr << val << "\n";
    }
};


int main(int argc, const char* argv[])
{
    std::shared_ptr<A> a_ptr {new A {}};

    return 0;
}

gives error: use of class template 'A' requires template arguments. Although I provide a default value for non-type template parameter and expect it to be seen and used by compiler somehow. What do I miss here ?

Thanks.

2
  • Yeah, it works fine with A<>, but I thought there is some way around A<>. Commented Nov 26, 2020 at 18:28
  • You can use A() :D. Jokes aside, you won't get around this for pure type inference (i.e. without an instance). That's why A a; will be fine, but std::shared_ptr<A<>> ptr; requires more. Commented Nov 26, 2020 at 18:30

2 Answers 2

5

It's still a template, and it still requires < and >:

std::shared_ptr<A<>> a_ptr {new A<> {}};

Think about this. If you have a function with a default parameter:

int foo(int baz=42);

Do you think you can simply call it without the parentheses?

int bar=foo;

Of course not, this won't work. You still need the parentheses:

int bar=foo();

Same thing with templates.

Sign up to request clarification or add additional context in comments.

2 Comments

Huh, I've used templates for years and never made the mental connection between function call syntax with default arguments and template instantiation with default arguments. This is a good answer
"Do you think you simply call it witout the parenthesis? ...Of course not..." Except that sometimes you can use templates without <>, so the "Of course not" is not appropriate here.
2

A doesn't name a class, it names a class template.

You need to use A<> to name the instantiation of the template that uses the default value:

std::shared_ptr<A<>> a_ptr {new A<> {}};
//              ^~~ here and    ^~~ here

If you are in or above, as is implied by the auto template parameter, you may remove the <> from A's construction since this qualifies as CTAD, but it's still needed in the type for shared_ptr

std::shared_ptr<A<>> a_ptr {new A {}};
//              ^~~ only here

Note: This only applies if there is no ambiguity to the type. If a constructor qualifies for CTAD, this will deduce a (possibly different) type than A<>

For example, if A were defined as:

template <typename T = int>
struct A
{
    A(){}
    A(T x){}
};

Then:

std::shared_ptr<A<>> a_ptr {new A {}};

would succeed, but

std::shared_ptr<A<>> a_ptr {new A {0.1}};

would fail, since new A {0.1} deduces A<double>, but A<> names A<int>

3 Comments

looks like there is should be another A<>, like std::shared_ptr<A<>> a_ptr {new A<> {}};
@Human-Compiler : I believe you need the A<> in the shared_ptr, not the new.
Whoops, thanks for the catch -- tried typing that quickly and was still the second answer. I've added some additional notes to indicate this. Also A {} only works since it qualifies for CTAD, but in more complex expressions can produce an ambiguity that is different from A<>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.