I'm trying to make the following function SFINAE-friendly:
#include <utility>
template <typename T, typename ...P>
T foo(P &&... params)
{
return {std::forward<P>(params)...};
}
I can't put a return
statement in a SFINAE context, but since this is an example of copy-list-initialization, I figured I could find a different example that is SFINAE-able.
There is T({...})
, but only GCC accepts it:
template <typename T, typename ...P>
T foo(P &&... params)
requires requires{T({std::forward<P>(params)...});}
{
return {std::forward<P>(params)...};
}
#include <array>
struct A
{
A(int) {}
A(const A &) = delete;
A &operator=(const A &) = delete;
};
int main()
{
foo<std::array<A, 3>>(1, 2, 3); // Error: call to implicitly-deleted copy constructor of `std::array`.
}
There is also foo({...})
(a function call). GCC and Clang accept it, but MSVC rejects it:
template <typename T>
void accept(T) noexcept;
template <typename T, typename ...P>
T foo(P &&... params)
requires requires{accept<T>({std::forward<P>(params)...});}
{
return {std::forward<P>(params)...};
}
How do I work around the compiler bugs, and write this SFINAE in a portable way?
CodePudding user response:
The second version works if you take const&
parameter in accept
:
template <typename T>
void accept(const T&) noexcept;
CodePudding user response:
If you remove extra parenthesis, it compiles for all compilers:
template <typename T, typename ...P>
T foo(P &&... params)
requires requires{T{std::forward<P>(params)...};}
{
return {std::forward<P>(params)...};
}