Home > Blockchain >  Template argument deduction with designated initializers
Template argument deduction with designated initializers

Time:08-31

I have the following peace of example code:

#include <array>
template<std::size_t N>
struct Cfg {
  std::array<int, N> Values;
  // ... more fields
}

constexpr Cfg c = {
  .Values = { 0, 1, 2, 3 }
};

Is it possible to deduce the template parameter N from the designated initializers? Using makeArray or initialize it with a defined array doesn't work either. Doing Cfg<4> for example works.

CodePudding user response:

The designated initializer is not relevant here. For the purpose of class template argument deduction it is just handled as if it was a usual element of the initializer list.

(At least that is how I read the standard. It is a bit unclear in [over.match.class.deduct] how a designated initializer ought to be handled when actually performing the overload resolution over the set of deduction guides.)


The problem is that there is no implicit deduction guide to deduce from the nested (untyped) braces, which can only deduce std::initializer_list and (reference to) array types, but your member is std::array. Or to be more precise the implicit aggregate deduction guide will not be formed under these circumstances.

Both

constexpr Cfg c = {
  .Values = { 0, 1, 2, 3 }
};

and

constexpr Cfg c = {
  { 0, 1, 2, 3 }
};

will fail, but both

constexpr Cfg c = {
  .Values = std::array{ 0, 1, 2, 3 }
};

and

constexpr Cfg c = {
  std::array{ 0, 1, 2, 3 }
};

will work since you now gave the initializer a type that the implicit aggregate deduction guide (since C 20) can deduce against the std::array member.


To make the syntax without explicit std::array work you will need to add a deduction guide that can deduce the size of the nested braced-init list, for example:

template<typename T, std::size_t N>
Cfg(const T(&)[N]) -> Cfg<N>;

MSVC and Clang do not accept this though, I am not sure why.

CodePudding user response:

This is possible with C 17's class template argument deduction:

#include <array>

template<std::size_t N>
struct Cfg {
    std::array<int, N> Values;
};

constexpr Cfg c {
    .Values = std::array { 0, 1, 2, 3 }
};

Try it live.

  • Related