我如何使c++ ADL查看模板的所有实例
How can I make C++ ADL to look into all instances of a template?
我遵循如何在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>)
。
我需要强制ADL
在writer<T,N>
的所有实例中进行搜索。我该怎么做呢?
为@T.C。提到ADL只查看相关的类,而writer
不是其中之一。(这就是为什么adl_flag
在flag
中声明-以便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");
}
相关文章:
- 如何使实例化在我的 OpenGL 程序中工作?
- 使类模板成为其自身的朋友,以进行不同的实例化
- 一种安全、符合标准的方法,使类模板专用化仅在实例化时才无法使用"static_assert"进行编译
- C++:如何使<T>模板化类的每个 T 的所有实例的 std::vector 静态?
- 当将 getline 与 int 一起使用时,如何修复"没有重载函数 'getline' 的实例与参数列表匹配"
- 使编译在模板类的特定实例化时失败
- 在每个实例中,使成员函数中的静态变量独立
- 如何实现赋值运算符,使多个实例共享公共数据
- 如何使递归函数在进入下一级循环之前读取每个新实例
- 如何使编译器在实例变量未初始化时C++生成错误或警告
- 如何使JNI RegisterNatives调用Java函数具有C++实例范围
- 使 Rscript 的实例保持打开状态
- 有没有办法使实例化unique_ptr不那么冗长
- 如何使链表与类的多个实例一起工作
- 如何使用线程来实例化多个 QApplication
- 自定义类的const实例化是否也会使类中的*everything*变为常量
- 如果实例化,如何使模板化变量专用化在编译时失败
- 受保护的构造函数,使基类不可实例化
- 如果使单一实例构造函数受到保护,缺点是什么 - 继承 - C++11.
- 如何使派生类的对象"reference"基类实例的成员?