This is my binary operator to concatenate tuples:
template <class... Args1, class... Args2>
constexpr decltype(auto) operator+(const std::tuple<Args1...> &tup1,
const std::tuple<Args2...> &tup2) {
return std::tuple_cat(tup1, tup2);
}
It works perfectly on both compiler (gcc, clang) with two tuples:
template <class Arg1, class Arg2>
constexpr decltype(auto) concat_test(Arg1 &&arg1, Arg2 &&arg2) {
return arg1 + arg2;
}
But when I try to use it in fold expression like follows:
template <class... Args>
constexpr decltype(auto) multiple_concat(Args &&... args) {
return (args + ...);
}
gcc 7.1.1 compiles it without any errors, unlike clang 5.0, which produces error output:
error: call to function 'operator+' that is neither visible in the template definition nor found by argument-dependent lookup
return (args + ... );
note: in instantiation of function template specialization 'multiple_concat < std::__1::tuple &, std::__1::tuple &>' requested here
multiple_concat (tup1, tup2);
note: 'operator+' should be declared prior to the call site
constexpr decltype(auto) operator +(const std::tuple &tup1, const std::tuple &tup2)
Is this code ill-formed and what exactly is clang talking about?
Aug 2018: Xcode 9.0 (roughly equivalent to open-source clang 4.0) still does not compile this code, while g++ does the job correctly.
I know it's painful not to be able to use the shiny new template fold syntax, but here's a workaround based on if constexpr
, the next best thing we can use.
template <typename T, typename... Ts>
constexpr decltype(auto) multiple_concat(T&& arg, Ts&&... rest) {
if constexpr (sizeof ...(rest) == 0) {
return arg;
}
else { // recursively concatenate the tuple
return arg + multiple_concat(std::forward<Ts>(rest) ...);
}
}
Clang happily compiles this code.
Apparently, unqualified lookup fails. This one makes it compile with Clang 6:
namespace std {
template <class... Args1, class... Args2>
constexpr decltype(auto) operator+(const ::std::tuple<Args1...> &tup1,
const ::std::tuple<Args2...> &tup2) {
return ::std::tuple_cat(tup1, tup2);
}
template <class... Args1, class... Args2>
constexpr decltype(auto) operator+(::std::tuple<Args1...> &&tup1,
::std::tuple<Args2...> &&tup2) {
return ::std::tuple_cat(tup1, tup2);
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.