[英]How to make C++ ADL to look into all instances of a template?
我正在關注如何在C ++教程中實現一個常量表達式計數器我正在嘗試修復C ++ 14沒有宏的反射,標記或外部工具..談話限制。
本教程的基本思想是:
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
個字段的類型。 請注意,它是友元函數,對於POD
類型的第N
個字段,編譯器將定義一個field_type(flag<N>)
。
對於decltype(field_type(flag<1>))
no matching function for call to 'field_type(flag<1>)
, g++
no matching function for call to 'field_type(flag<1>)
給出no matching function for call to 'field_type(flag<1>)
。
我需要以某種方式強制ADL
在writer<T,N>
所有實例中進行搜索。 我怎樣才能做到這一點?
更新
作為@TCmentioned 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");
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.