0

When using a templated struct as an argument to another templated struct, I've run into some conditions in which automatic template deduction fails. How can I write deduction guides for these three conditions?

#include <cstddef>
#include <array>

template <size_t N>
struct A_args {
    std::array<int, N> a;
};

template <size_t N>
struct A {
    std::array<int,N> a;

    A(A_args<N> const& aa): a{aa.a} {};
};

int main() {
    A_args a{std::array{1,2,3,4}};

    // Able to deduce N
    auto b = A(a);

    // Able to deduce N
    auto c = A(A_args{std::array{1,2,3,4}});

    // Unable to deduce N
    auto d = A({std::array<int,4>{1,2,3,4}});
}
template <typename T>
struct A_args {
    T a {};
};

template <typename T>
struct A {
    A(A_args<T> const& aa = {}) : a{aa.a} {};
    
    T a;
};

int main() {
    // Unable to deduce T
    auto a = A_args{4};

    // Unable to deduce T
    auto b = A{{.a = 2}};
}

edited, adding:

#include <cstddef>
#include <array>

template <class... T>
constexpr bool always_false = false;

// Able to deduce N
// Test: deduce from method parameter
template<size_t N>
struct A {
    std::array<int, N> a;

    A(std::array<int, N> const& a): a{a} {};
};

// Able to deduce N
// Test: deduce from method parameter with inheritance
template <size_t N>
struct A1 : A<N> {
    A1(std::array<int, N> const& a): A<N>{a} {};
};

// Able to deduce N
// Test: deduce from method parameter with inheritance and an extra type parameter
template <typename T, size_t N>
struct A2 : A<N> {
    static_assert(always_false<T>, "virtual");
};

template <size_t N>
struct A2<int, N> : A<N> {
    A2(std::array<int, N> const& a): A<N>{a} {};
};

// Unable to deduce N
// Test: deduce from method parameter with implicit type parameter
// Question: Is there a better method to formulate A<0> from this virtual(-ish) class?
template <typename T>
struct A3 : A<0> {
    static_assert(always_false<T>, "virtual");
};

template <size_t N>
struct A3<int> : A<N> {
    A3(std::array<int, N> const& a): A<N>{a} {};
};


int main() {
    std::array a {1,2,3,4};

    // Able to deduce N
    auto b = A(a);
    auto c = A1(a);
    auto d = A2<int, 4>(a);

    // Unable to deduce N
    auto e = A3<int>(a);
    auto e = A3(a);
}
rturrado
  • 7,699
  • 6
  • 42
  • 62
user19087
  • 1,899
  • 1
  • 16
  • 21
  • Sounds impossible. Why would you want to do this? – 康桓瑋 Jun 11 '22 at 18:31
  • To simplify my interface. Are they all impossible? For example, how does `std::array {1,2}` deduce its type? Shouldn't that also apply to `A_args {4}`? – user19087 Jun 11 '22 at 18:33
  • "*Shouldn't that also apply to `A_args {4}`?*" That's [P1816](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1816r0.pdf), which has been implemented by [GCC as well as MSVC](https://godbolt.org/z/T4sesn7cv). – 康桓瑋 Jun 11 '22 at 18:38
  • `template A(std::initializer_list>) -> A;` works for your first case, but I don't think it's a recommended way. – 康桓瑋 Jun 11 '22 at 18:42
  • @康桓瑋: Right, that doesn't work with mixed types given more than one member or designated initializers. The first case - the one I prefer to solve - I don't understand why the compiler can't deduce template parameter `N`. The constructor receives an initializer list, but not one that can be represented with `std::initializer_list` because of the mixed types. It knows the initializer list can be a valid `A_args`, but it can't deduce `N` because ... ? – user19087 Jun 11 '22 at 20:33
  • Would a recursive deduction guide be able to force the compiler to first evaluate the type of the initialization list? – user19087 Jun 11 '22 at 20:44
  • Add a constructor `A(std::array)` to your `A` class. Then have the original ctor delegate to that since they practically do the same thing. I'm uder the impression you won't need deduction guides for that case, but even if you two it won't collide with the original ones – Nikos Athanasiou Jun 11 '22 at 21:10
  • Unfortunately that's not compatible with the [named/optional parameters](https://pdimov.github.io/blog/2020/09/07/named-parameters-in-c20/) idiom. – user19087 Jun 11 '22 at 21:33

0 Answers0