我如何使c++ ADL查看模板的所有实例

How can I make C++ ADL to look into all instances of a template?

本文关键字:实例 何使 c++ ADL      更新时间:2023-10-16

我遵循如何在c++中实现常量表达式计数器教程我试图修复 c++ 14 Reflections Without Macros, Markup and External tools talk限制。

本教程的基本思想是:

template<int N>
struct flag {
  friend constexpr int adl_flag (flag<N>);
};
template<int N>
struct writer {
   friend constexpr int adl_flag (flag<N>) { return N; }
   static constexpr int value = N;
};
template<int N, class = char[noexcept(adl_flag(flag<N> ()))?+1:-1]>
int constexpr reader (int, flag<N>) { return N; }
template<int N>
int constexpr reader (float, flag<N>, int R = reader (0, flag<N-1>())) { return R; }
int constexpr reader (float, flag<0>) { return 0; }
template<int N = 1, int C = reader (0, flag<32> ())>
int constexpr next (int R = writer<C + N>::value) { return R; }
int main () {
  constexpr int a = next ();
  constexpr int b = next ();
  constexpr int c = next ();
  // YES! it works!!!
  static_assert (a == 1 && b == a+1 && c == b+1, "try again");
}

注意:如果你现在不感兴趣,是时候停止阅读了:-)

讲座解释了如何使用聚合初始化和隐式转换操作符提取POD类型的字段数和字段类型,但主要限制是只支持基本类型。

我已经提供了以上背景来证明我的动机!

当我把这两种方法结合起来时,我得到了这个:

template<int N>
struct flag {
  friend constexpr int adl_flag (flag<N>);
};
template<typename T, int N>
struct writer {
  friend constexpr int adl_flag (flag<N>) {
    return N;
  }
  friend constexpr T field_type(flag<N>) { return T{}; }
  static constexpr int value = N;
};

field_type(flag<N>)将给我N第1个字段的类型。注意,这是一个友元函数,对于N, POD类型的第3个字段,编译器将只定义一个field_type(flag<N>)

g++decltype(field_type(flag<1>))no matching function for call to 'field_type(flag<1>)

我需要强制ADLwriter<T,N>的所有实例中进行搜索。我该怎么做呢?

为@T.C。提到ADL只查看相关的类,而writer不是其中之一。(这就是为什么adl_flagflag中声明-以便ADL可以找到它。)

在不知道T值的情况下如何使writer成为关联类,以便ADL可以找到它?

field_type声明添加到标志模板中,返回类型为auto(仅在c++ 14之后可用)

仅适用于gcc 4.9:

#include <type_traits>
template<int N>
struct flag {
    friend constexpr int adl_flag (flag<N>);
    friend constexpr auto field_type(flag<N>);
};
template<typename T, int N>
struct writer {
    friend constexpr int adl_flag (flag<N>) { return N; }
    friend constexpr auto field_type(flag<N>) { return (T&&)(*(T*)0); }  // remove default constructable restriction
    static constexpr int value = N;
};
template<int N, class = char[noexcept(adl_flag(flag<N> ()))?+1:-1]>
int constexpr reader (int, flag<N>) { return N; }
template<int N>
int constexpr reader (float, flag<N>, int R = reader (0, flag<N-1>())) { return R; }
int constexpr reader (float, flag<0>) { return 0; }
template<typename T, int N = 1, int C = reader (0, flag<32> ())>
int constexpr next (int R = writer<T, C + N>::value) { return R; }
int main () {
    constexpr int a = next<int> ();
    constexpr int b = next<double> ();
    constexpr int c = next<long> ();
    // YES! it works!!!
    static_assert (a == 1 && b == a+1 && c == b+1, "try again");
    static_assert(std::is_same<decltype(field_type(flag<1>{})), int>{}, "first is int");
    static_assert(std::is_same<decltype(field_type(flag<2>{})), double>{}, "second is double");
    static_assert(std::is_same<decltype(field_type(flag<3>{})), long>{}, "third is long");
}

使用自动函数的decltype而不是noexcept,适用于gcc 5.2, clang 3.5.1 - 3.7.1:

#include <type_traits>
template <int N>
struct flag {
    constexpr friend auto adl_flag(flag<N>);
    friend auto field_type(flag<N>);
};
template<typename T, int N>
struct writer {
    friend constexpr auto adl_flag(flag<N>) { return 0; }
    friend auto field_type(flag<N>) { return (T&&)(*(T*)0); }
    static constexpr int value = N;
};
template<int N, class = decltype(adl_flag(flag<N>{}))>
int constexpr reader (int, flag<N>) { return N; }
template<int N>
int constexpr reader (float, flag<N>, int R = reader (0, flag<N-1>())) { return R; }
int constexpr reader (float, flag<0>) { return 0; }
template<typename T, int N = 1, int C = reader (0, flag<32> ())>
int constexpr next (int R = writer<T, C + N>::value) { return R; }
int main () {
    constexpr int a = next<int> ();
    constexpr int b = next<double> ();
    constexpr int c = next<long> ();
    // YES! it works!!!
    static_assert (a == 1 && b == a+1 && c == b+1, "try again");
    static_assert(std::is_same<decltype(field_type(flag<1>{})), int>{}, "first is int");
    static_assert(std::is_same<decltype(field_type(flag<2>{})), double>{}, "second is double");
    static_assert(std::is_same<decltype(field_type(flag<3>{})), long>{}, "third is long");
}