2
votes

I am learning about the auto template deduction guid: https://en.cppreference.com/w/cpp/language/class_template_argument_deduction. Therefore I wanted to try this out.

I have the following nested class structure in which MyClass is a templated class with non template parameter, and the inner struct MyStruct simply have an std::array<int, N>.

I have MyStruct mStruct; as member:

#include <iostream>
#include <array>

template<size_t N>
class MyClass
{
public:
   struct MyStruct
   {
      using ArrayType = std::array<int, N>;
      ArrayType arr;
   };
   MyStruct mStruct;

   MyClass(typename MyStruct::ArrayType const& arr)
      : mStruct{ arr }
   {}
};
// deduction guid
template<size_t N>
MyClass(typename MyClass<N>::MyStruct::ArrayType)->MyClass<N>;

I want to achive or construct the MyClass like this

 MyClass myObj{ typename MyClass<2>::MyStruct::ArrayType{ 1, 2} };

therefore I gave the deduction guid as above.

This code was working in MSVC 2019: https://godbolt.org/z/7PzzbM

Then wanted to see the compiler out for the other GCC and Clang. But they did not accept my code: https://godbolt.org/z/M8cPKj

error:

source > : In function 'int main()' :
   <source> : 25 : 67 : error : class template argument deduction failed :
25 | MyClass myObj{ typename MyClass<2>::MyStruct::ArrayType{ 1, 2} };
| ^
<source>:25 : 67 : error : no matching function for call to 'MyClass(MyClass<2>::MyStruct::ArrayType)'
< source > : 15 : 4 : note : candidate : 'template<long unsigned int N> MyClass(const typename MyClass<N>::MyStruct::ArrayType&)-> MyClass<N>'
15 | MyClass(typename MyStruct::ArrayType const& arr)
| ^ ~~~~~~
<source> : 15 : 4 : note : template argument deduction / substitution failed :
<source> : 25 : 67 : note : couldn't deduce template parameter 'N'
25 | MyClass myObj{ typename MyClass<2>::MyStruct::ArrayType{ 1, 2} };
| ^
<source>:5 : 7 : note : candidate : 'template<long unsigned int N> MyClass(MyClass<N>)-> MyClass<N>'
5 | class MyClass
| ^ ~~~~~~
<source> :5 : 7 : note : template argument deduction / substitution failed :
<source> : 25 : 67 : note : 'std::array<int, 2>' is not derived from 'MyClass<N>'
25 | MyClass myObj{ typename MyClass<2>::MyStruct::ArrayType{ 1, 2} };
| ^
<source>:21 : 1 : note : candidate : 'template<long unsigned int N> MyClass(typename MyClass<N>::MyStruct::ArrayType)-> MyClass<N>'
21 | MyClass(typename MyClass<N>::MyStruct::ArrayType)->MyClass<N>;
| ^ ~~~~~~
<source>:21 : 1 : note : template argument deduction / substitution failed :
<source> : 25 : 67 : note : couldn't deduce template parameter 'N'
25 | MyClass myObj{ typename MyClass<2>::MyStruct::ArrayType{ 1, 2} };
| ^
ASM generation compiler returned : 1
  • Have I done the deduction guide correctly?
  • Which compiler is correct?

Really sorry, if this is a silly mistake of mine, but the compilers; shouldn't they behave correctly?

1
That seems an odd way to construct the object. Why have a deduction guide if you specify the argument to the constructor? Wouldn't MyClass myObj{ { 1, 2} }; make more sense? - cigien
@cigien Yes, that was the idea: godbolt.org/z/5Pdvjv But I was getting error in MSVC: Then I though I need to tell the type explictly. - LernerCpp
No, the idea is right, just the deduction guide is wrong. I'll post an answer. - cigien
Your deduction guide contains a single parameter and that one is a non-deduced context. It cannot work. - StoryTeller - Unslander Monica
@StoryTeller-UnslanderMonica Could you elaburate that? Why MSVC was still accepting it? - LernerCpp

1 Answers

3
votes

You can write a deduction guide that considers the brace-initializer-list argument as an array like this:

template<size_t N>
MyClass(int const (&)[N]) -> MyClass<N>;

and then you can construct an object this way:

MyClass myObj{ { 1, 2} };

Here's a demo.