I'm making it using multi inheritance with a pair struct that contains an index and the type of the element in a recursive structure like this:
template<int index, typename... ts>
struct ok;
template<int index, typename t>
struct ok<index,t>
{
t val;
};
template<int index, typename t, typename... ts>
struct ok<index,t,ts...> : ok<index + 1, ts...>
{
t val;
}
It also contains a function fu (not shown here) that in the specialized version (the one that SHOULD always be used) is called when a template int 'index2' is the same as the pair's index and simply prints something for confirmation that it has been called.
The main tuple inherits the first pair:
template<typename... xs>
struct bok : ok<0,xs...>
{
};
The problem is that it only calls fu for the first pair and not the inherited pairs from the first pair that actually have the corresponding index.
Output of the code:
index:2
index:1
index:0
right: 0
wrong: 0 1
wrong: 0 2
I tried having the pairs contain the next one recursively but that doesn't work either.
How can I fix this?
Here's all the code: (MSVC C++20)
#include <iostream>
using std::cout;
template<int index, typename... ts>
struct ok;
template<int index, typename t>
struct ok<index,t>
{
ok()
{
cout << "index:" << index << '\n';
}
t val;
template<int index2>
void fu()
{
cout << "wrong: " << index << ' ' << index2 << '\n';
}
template<>
void fu<index>()
{
cout << "right: " << index << '\n';
};
};
template<int index, typename t, typename... ts>
struct ok<index,t,ts...> : ok<index + 1, ts...>
{
t val;
ok()
{
cout << "index:" << index << '\n';
}
// fu prints the index of the pair the was called
// if the indexes arent the same (the problem) it calls the non
// specialized version of the function
template<int index2>
void fu()
{
cout << "wrong: " << index << " " << index2 << '\n';
};
// if the indexes corresponds (should always happen) then this is called
template<>
void fu<index>()
{
cout << "right: " << index << '\n';
};
};
template<typename... xs>
struct bok : ok<0,xs...>
{
// *tries* to call 'fu' for the pair the corresponding index
template<int index>
void gh()
{
this->fu<index>();
}
};
int main()
{
bok<int, int, float> lo;
lo.gh<0>();
lo.gh<1>();
lo.gh<2>();
}
When member functions are introduced into derived classes they hide the visibility of the members of the same name in their base classes. Your fu method in ok<0, xs...> takes priority over the other members from its base classes.
You can reintroduce these names with a using statement but this still won't help. Even with a using statement the base class member functions will still be hidden if a derived class member has a member function with the same name and parameter list. Technically your fu methods do have different names since they're templates, but I'm referring to standard-compliant compilers here like gcc and clang. The fact that you can explicitly specialize fu in the ok<> class template is not standard. This is probably an extension in MSVC.
To solve this you'll have to modify fu in such a way that it has a different parameter list for each instantiation of ok<>. You can do this by having it take a dummy tag in its parameter list in both specializations:
void fu(index_tag<index>) { cout << "right: " << index << '\n'; }
Now they have unique parameter lists and a using statement will populate the derived class with those members:
template <int index, typename t, typename... ts>
struct ok<index, t, ts...> : ok<index + 1, ts...> {
// ...
using ok<index + 1, ts...>::fu;
// ...
};
Now bok can be changed to...
template <typename... xs>
struct bok : ok<0, xs...> {
template <int index>
void gh() {
this->fu(index_tag<index>{});
}
};
Full code:
#include <iostream>
using std::cout;
template <int I>
struct index_tag {};
template <int index, typename... ts>
struct ok;
template <int index, typename t>
struct ok<index, t> {
ok() { cout << "index:" << index << '\n'; }
t val;
void fu(index_tag<index>) { cout << "right: " << index << '\n'; }
template <int index2>
void fu(index_tag<index2>) {
cout << "wrong: " << index2 << " is out of range.\n";
}
};
template <int index, typename t, typename... ts>
struct ok<index, t, ts...> : ok<index + 1, ts...> {
t val;
ok() { cout << "index:" << index << '\n'; }
using ok<index + 1, ts...>::fu;
void fu(index_tag<index>) { cout << "right: " << index << '\n'; }
};
template <typename... xs>
struct bok : ok<0, xs...> {
template <int index>
void gh() {
this->fu(index_tag<index>{});
}
};
int main() {
bok<int, int, float> lo;
lo.gh<0>();
lo.gh<1>();
lo.gh<3>();
}