【问题标题】:How to make C++ ADL to look into all instances of a template?如何让 C++ ADL 查看模板的所有实例?
【发布时间】:2017-02-21 20:13:53
【问题描述】:

我正在关注How to implement a constant-expression counter in C++ 教程并且我正在尝试修复C++14 Reflections Without Macros, Markup nor External Tooling.. 通话限制。

本教程的基本思想是这样的:

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&lt;N&gt;) 会给我Nth 字段的类型。 请注意,它是一个友元函数,对于 POD 类型的 Nth 字段,编译器将定义一个 field_type(flag&lt;N&gt;)

g++ 给我no matching function for call to 'field_type(flag&lt;1&gt;)decltype(field_type(flag&lt;1&gt;))

我需要以某种方式强制ADL 搜索writer&lt;T,N&gt; 的所有实例。 我该怎么做?

更新

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

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

【问题讨论】:

  • 考虑到委员会将禁止整个柜台的事情,我认为花时间在这方面没有意义。
  • 无论如何,ADL(这与 ODR 无关)只查看关联的类,writer 不是其中之一。 (这就是为什么在 flag 中声明 adl_flag - 以便 ADL 可以找到它。)
  • @T.C. the committee is going to ban the whole counter thing 可以提供一个表明这是他们意图的参考吗?元计数器使用的 ADL 规则是旧的。委员会将如何在不破坏数百万行代码的情况下更改规则!
  • “是的!它有效!!!”在我尝试过的任何编译器中都没有。您添加的 noexcept 内容与原始帖子不同。

标签: c++ c++11 c++14 template-meta-programming constexpr


【解决方案1】:

在标志模板中添加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 的 auto 函数而不是 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");

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-09
    • 2014-03-13
    相关资源
    最近更新 更多