I'm trying to write generic function that iterates through std::tuple
elements. In doing so, i need to extract the element type of the given tuple element that is being processed. However, i'm running into an issue regarding type equality between the extracted type and the actual type of the tuple element. The below code illustrates the problem by adding static_assert
s to the extracted type, which (as far as i can tell) should be true in both cases:
#include <tuple>
#include <type_traits>
using TestTuple = std::tuple<int>;
template <std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
foo(std::tuple<Tp...> &) {}
template <std::size_t I = 0, typename... Tp>
inline typename std::enable_if <
I<sizeof...(Tp), void>::type foo(std::tuple<Tp...> &output) {
// Using tuple element
using ValueType = std::tuple_element<I, std::tuple<Tp...>>;
static_assert(std::is_same<ValueType, int>::value, "Should be true");
using ValueType2 = std::remove_reference<decltype(std::get<I>(output))>;
static_assert(std::is_same<ValueType2, int>::value, "Should be true");
}
void bar() {
TestTuple t;
foo(t);
}
Trying to compile through Compiler Explorer, both static_assert
s fail on both GCC 11.2 and clang-13; clang output is:
<source>:16:5: error: static_assert failed due to requirement 'std::is_same<std::tuple_element<0, std::tuple<int>>, int>::value' "Should be true"
static_assert(std::is_same<ValueType, int>::value, "Should be true");
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:24:5: note: in instantiation of function template specialization 'foo<0UL, int>' requested here
foo(t);
^
<source>:19:5: error: static_assert failed due to requirement 'std::is_same<std::remove_reference<int &>, int>::value' "Should be true"
static_assert(std::is_same<ValueType2, int>::value, "Should be true");
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 errors generated.
Compiler returned: 1
CodePudding user response:
You're not getting the type of the element of the tuple correctly. They should be
using ValueType = typename std::tuple_element<I, std::tuple<Tp...>>::type;
// ^^^^^^^^ ^^^^^^
static_assert(std::is_same<ValueType, int>::value, "Should be true");
using ValueType2 = typename std::remove_reference<decltype(std::get<I>(output))>::type;
// ^^^^^^^^ ^^^^^^
static_assert(std::is_same<ValueType2, int>::value, "Should be true");
Or (since C 14)
using ValueType = std::tuple_element_t<I, std::tuple<Tp...>>;
// ^^
static_assert(std::is_same<ValueType, int>::value, "Should be true");
using ValueType2 = std::remove_reference_t<decltype(std::get<I>(output))>;
// ^^
static_assert(std::is_same<ValueType2, int>::value, "Should be true");