Home > Mobile >  Alternative to template ADL for GCC <= 10
Alternative to template ADL for GCC <= 10

Time:11-19

Consider the following valid C 20 code:

#include <utility>

namespace foo
{
  template<typename... Args>
  struct tuple : Args... { };

  template<std::size_t N, typename... Args>
  auto get(tuple<Args...>) { return 0; }
}

namespace bar
{
  template<typename... Args>
  struct tuple : Args... { };

  template<std::size_t N, typename... Args>
  auto get(tuple<Args...>) { return 0; }
}

template<class Tuple, std::size_t... N>
auto for_each(Tuple& args, std::index_sequence<N...>) {
  (get<N>(args), ...);
}

int main()
{
  struct test { };
  foo::tuple<test> t;
  for_each(t, std::make_index_sequence<1>());
}

Here, get<N> is able to be resolved through ADL thanks to a C 20 addition (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0846r0.html)

My question is, what are the workarounds to this before C 20, which do not require the method for_each to know about the foo and bar namespaces ?

I'd be happy with anything that works starting from GCC 8.

CodePudding user response:

You can add a dummy function and leave it without definition to make the compiler happy.

When the template is instatiated the right methods will be found through ADL.

#include <utility>
#include <tuple>

namespace foo
{
  template<typename... Args>
  struct tuple : Args... { };

  template<std::size_t N, typename... Args>
  auto get(tuple<Args...>) { return 0; }
}

namespace bar
{
  template<typename... Args>
  struct tuple : Args... { };

  template<std::size_t N, typename... Args>
  auto get(tuple<Args...>) { return 0; }
}

template <typename... T>
struct Dummy;

template <std::size_t N, typename... Args>
auto get(Dummy<Args...>);

template<class Tuple, std::size_t... N>
auto for_each(Tuple& args, std::index_sequence<N...>) {
  (get<N>(args), ...);
}

int main()
{
  struct test { };
  foo::tuple<test> t;
  for_each(t, std::make_index_sequence<1>());
}

Edit As suggested by @Jarod42 we can do

template <std::size_t N>
void get() = delete;

The compiler can't rule out that there is a valid specialization for that template later on, so the fact that it's deleted doesn't really matter here.

  • Related