First, I am really sorry for the poor quality of this code, but I have already spent 1 hour to isolate the source of my problems and I do not have a shorter example than this. So here is the code:
#include <iostream>
#include <type_traits>
#include <utility>
#include <tuple>
#include <array>
template <class Crtp, class... Types>
struct Base
{
template <
unsigned int Index,
class Type = typename std::tuple_element<Index, std::tuple<Types...> >::type
>
inline const Type& get() const {
return std::get<Index>(data);
}
template <
unsigned int Index,
class Type = typename std::tuple_element<Index, std::tuple<Types...> >::type
>
inline Crtp& set(const Type& value) {
std::get<Index>(data) = value; return static_cast<Crtp&>(*this);
}
std::tuple<Types...> data;
};
template <typename Type, unsigned int Size>
struct Derived : public Base<Derived<Type, Size>, std::array<Type, Size>>
{
template <
class... Args,
class Template = decltype(std::declval<const Base<
Derived<Type, Size>,
std::array<Type, Size>
>>().template get<0>(std::declval<Args>()...))
>
inline Template test(Args&&... args) const {
return this->template get<0>(std::forward<Args>(args)...);
}
template <
class... Args,
class Template = decltype(std::declval<const Base<
Derived<Type, Size>,
std::array<Type, Size>
>>().template set<0>(std::declval<Args>()...))
>
inline Derived<Type, Size>& test(Args&&... args) {
return this->template set<0>(std::forward<Args>(args)...);
}
static void check() {
Derived<double, 3> derived;
std::cout<<derived.test()[0]<<std::endl;
}
};
int main(int argc, char* argv[])
{
Derived<double, 3> derived;
std::cout<<derived.test()[0]<<std::endl; // Working
Derived<double, 3>::check(); // Not working: error: no match for ‘operator[]’ (operand types are ‘Derived<double, 3u>’ and ‘int’)
return 0;
}
Explanation of what is done:
There is a Base
class that takes a derived class (CRTP) and tuple types as template arguments. This base class has two members: one to get
the n-th element of the tuple
, the other to set
the n-th element of the tuple
.
Then, there is a Derived
class that inherits from the Base
class and put a std::array
in the tuple of the base class: consequently, the type of data of this derived class is : std::tuple<std::array<Type, Size>> data
. This derived class has an overloaded function test()
which calls the get
or set
function depending on its argument: test()
will call get()
but test(std::array<double, 3>{1, 2, 3})
will call set(std::array<double, 3>{1, 2, 3})
. Consequently test()[0]
should return the first element of the array: it works in the main()
, but it does not work in a static function.
I do not know what the compiler is trying to do, but apparently this is not working.
I think that this is a bug in g++ 4.8.1
(I have not tried other versions) but I wanted to be sure of that.
So here are my questions:
- Can you confirm this bug (and maybe find an explanation)?
- Do you have a shorter and less complicated example to illustrate the problem?