Home > Software design >  Is it possible to use fold expression in class template deduction guide?
Is it possible to use fold expression in class template deduction guide?

Time:04-03

I did a simple test as follow:

#include <iostream>

template <typename T, std::size_t N, std::size_t D> struct MyArray {
    template <typename First, typename ... Rest> MyArray(First, Rest...);
    int dimension[N];
    T m_array[D];
};

template <typename First, typename... Rest> MyArray(First first, Rest... values)
    -> MyArray<First, 1   sizeof...(values), (values * ...)>;

int main()
{
    MyArray arr{3, 2, 3};
    return 0;
}

The compiler complains about it:

main.cpp:14:13: No viable constructor or deduction guide for deduction of template arguments of 'MyArray'
main.cpp:4:50: candidate template ignored: couldn't infer template argument 'T'
main.cpp:9:45: candidate template ignored: substitution failure [with First = int, Rest = <int, int>]: non-type template argument is not a constant expression
main.cpp:3:60: candidate function template not viable: requires 1 argument, but 3 were provided

If I replace (values * ...) with 18 everything works as expected. Is there any way to benefit from fold expressions in deduction guides in C ?

CodePudding user response:

You cannot use the values of function arguments inside constant expressions and here in particular not in a template argument.

If you want to deduce the type differently for different values, you need to make sure that the type also differs from value to value.

Example:

#include<type_traits>

template<auto V>
constexpr auto constant = std::integral_constant<decltype(V), V>{};

//...

MyArray arr{3, constant<2>, constant<3>};

As far as I can tell this should work with your deduction guide as is, although both GCC and MSVC seem to have problems with this code, which look like bugs to me.

std::integral_constant is implicitly convertible to the value in its template argument. This conversion doesn't require accessing the value of a given instant of the type, so (values * ...) should be fine.

sizeof...(values) is always fine, since it doesn't access values at all. It just expands to the number of items in the pack.

GCC claims (values * ...) doesn't contain an unexpanded pack, which seems wrong to me. MSVC has an internal compiler error, which is definitively a bug. But Clang accepts the variation.

  • Related