2

I have a class A which contains a templated member B whose exact type should be deduced from A's constructor. The way this is supposed to work is that, as shown in the below example, B can be instantiated with either 1 or 2 parameters to its constructor (deduction guide will tell) but will take a const char* in any case. When I instantiate A with the const char* argument for the constructor, an object B should be instantiated from the const char* as A only takes a B object. However, this is how far I get:

#include <iostream>

template <bool LengthOpt>
struct B
{
    B(const char*) { }

    B(const char*, size_t) {  }

    void print() {
        if constexpr (LengthOpt) {
            std::cout << "LengthOpt is set" << std::endl;
        }
    }
};

B(const char*) -> B<false>;
B(const char*, size_t) -> B<true>;


template <template <bool LengthOpt> class T>
struct A
{
    A(T is) : is_{is} {
        
    }

    void print() {
        is_.print();
    }

    T is_;
};

int main()
{
    A a("hello");

    a.print();
}

And it yields those errors:

<source>:24:7: error: use of template template parameter 'T' requires template arguments; argument deduction not allowed in function prototype
    A(T is) : is_{is} {
      ^
<source>:21:43: note: template is declared here
template <template <bool LengthOpt> class T>
                                          ^
<source>:32:5: error: use of template template parameter 'T' requires template arguments; argument deduction not allowed in non-static struct member
    T is_;
    ^
<source>:21:43: note: template is declared here
template <template <bool LengthOpt> class T>
                                          ^
<source>:37:7: error: no viable constructor or deduction guide for deduction of template arguments of 'A'
    A a("hello");
      ^
<source>:22:8: note: candidate template ignored: could not match 'A<T>' against 'const char *'
struct A
       ^
<source>:22:8: note: candidate function template not viable: requires 0 arguments, but 1 was provided

My take on the problem is that the compiler doesn't know that I want to instantiate an object B in A's constructor, as the template template argument specifies nothing. It could very well be just any object that takes one template parameter.

I'm scratching my head right now on how to resolve this. Is it even possible or am I scratching a limitation in C++ again?

康桓瑋
  • 33,481
  • 5
  • 40
  • 90
glades
  • 3,778
  • 1
  • 12
  • 34
  • 2
    `T` is a template not a type. You need not use a template template parameter to make `A` use some intstantiation of `B`. – 463035818_is_not_an_ai Jun 02 '22 at 09:11
  • If `A` only takes `B`, it would be a good idea to reflect it in the template, as it stands now, you allow any template template parameter for `T`, not just `B`. Maybe `template class A{ A(B arg); };`? – Quimby Jun 02 '22 at 09:13
  • Why not provide extra constructor+deduction guide? https://godbolt.org/z/ThhsGjdzc – alagner Jun 02 '22 at 09:20
  • @463035818_is_not_a_number You're right, but I would still have to deduce the specialization of B somehow. I figured it doesn't really work as overload resolution is only considered AFTER template instantiation is done. – glades Jun 03 '22 at 08:59
  • @Quimby: I tried that but then B can't be deduced – glades Jun 03 '22 at 09:00
  • @alagner I guess I would have to do that, I see that as the only way. However, in this case I'd rather adapt my interface :) – glades Jun 03 '22 at 09:01
  • "deduce the specialization of B somehow". Do you mean you want to get `T` from `B` ? – 463035818_is_not_an_ai Jun 03 '22 at 09:02
  • @463035818_is_not_a_number yes, and have the compiler do so according to B's deduction guides. But I can't get that to work somehow – glades Jun 03 '22 at 09:16
  • I wonder if the existence of the function `std::make_pair` in the Standard is an indication that `C++` will not deduce template parameters on constructors. Otherwise I could write `std::pair( 23, 4.5)` instead of `std::pair< int, float>( 23, 4.5)` and wouldn't need std::make_pair`. – Mark Roberts Jun 03 '22 at 11:47
  • @MarkRoberts What do you mean? You can actually do that with C++17, it's called CTAD. The problem in question here is not about CTAD though but about the interaction between template argument deduction and implicit conversions / overload resolution. – glades Jun 03 '22 at 11:58
  • @glades: Modern times indeed! Thanks for the update. – Mark Roberts Jun 03 '22 at 12:07

0 Answers0