结构中的类型注入
Type injection in structs
我想我问的不可能,但我想完全确定,所以我还是问了..
我想从未在模板中传递但以其他方式注入的模板化结构(可用于 constexpr 函数)中获取编译时值。
很难解释,我会尝试一些代码:
template<int A>
struct MagicStruct
{
enum { current = A, injected = /* magic */}
};
template<int A, int B>
struct InjectionStruct
{
enum { first=A, second=B}
/*... injection of B in MagicStruct<A> ... */
};
static const int AVALUE = 1;
static const int BVALUE = 2;
static const int CVALUE = InjectionStruct<AVALUE, BVALUE>::first; //== 1
static const int CVALUE = InjectionStruct<AVALUE, BVALUE>::second; //== 2
static const int DVALUE = MagicStruct<AVALUE>::injection; //== 2
是否有一些我不知道的技巧允许这样做?
[编辑] 我想在输入中使用 AVALUE 作为模板参数来获取 DVALUE
以下内容对您有帮助吗?
template<int A, int B>
struct InjectionStruct
{
constexpr static int first = A;
constexpr static int second = B;
constexpr static int MAGIC = B;
};
template<int A, class Injection>
struct MagicStruct
{
constexpr static int current = A;
constexpr static auto injected = Injection::MAGIC;
};
static const int AVALUE = 1;
static const int BVALUE = 2;
static const int CVALUE = InjectionStruct<AVALUE, BVALUE>::first; //== 1
static const int CVALUE = InjectionStruct<AVALUE, BVALUE>::second; //== 2
static const int DVALUE = MagicStruct<AVALUE, InjectionStruct<AVALUE, BVALUE>>::injected; //== 2
很难给出更深入的建议,不知道你想注入什么。
您需要 InjectionStruct
和 MagicStruct
之间的某种关系。出于这个原因,我为 injected
值和 InjectionStruct
中的 typdef
添加了一个额外的模板参数。
第一个例子使用InjectionStruct
本身来定义具体的MagicStruct:
示例:
// MagicStruct is generic
template<int A, int INJ>
struct MagicStruct
{
enum { current = A, injected = INJ};
};
// Injection struct has it own copy of MagicStruct
template<int A, int B>
struct InjectionStruct
{
enum { first=A, second=B};
// Provide custom magic number
constexpr static int provideInjection(){ return B;}
// Own copy of magicStruct, injected by this template instance.
template <int X> struct MagicStruct: public ::MagicStruct<X,provideInjection()>{};
};
constexpr static const int AVALUE = 1;
constexpr static const int BVALUE = 2;
constexpr static const int CVALUE1 = InjectionStruct<AVALUE, BVALUE>::first; //== 1
constexpr static const int CVALUE2 = InjectionStruct<AVALUE, BVALUE>::second; //== 2
// Using a specific InjectionStruct, provies the MagicStruct with one argument.
constexpr static const int DVALUE3 = InjectionStruct<AVALUE, BVALUE>::MagicStruct<AVALUE>::injected; //== 2
int main()
{
std::cout << CVALUE1 << std::endl;
std::cout << CVALUE2 << std::endl;
std::cout << DVALUE3 << std::endl;
return 0;
}
在下面的解决方案中,MagicStruct
从默认值 InjectionStruct
中获取魔法值,即修复。
// InjectionStruct is generic.
template<int A, int B>
struct InjectionStruct
{
enum { first=A, second=B};
constexpr static int provideInjection(){ return A+B;}
};
constexpr static const int AVALUE = 1;
constexpr static const int BVALUE = 2;
// Define MagicStruct based on a specific InjectionStruct
template<int A, int INJ = InjectionStruct<A,BVALUE>::provideInjection()>
struct MagicStruct
{
enum { current = A, injected = INJ};
};
constexpr static const int CVALUE1 = InjectionStruct<AVALUE, BVALUE>::first; //== 1
constexpr static const int CVALUE2 = InjectionStruct<AVALUE, BVALUE>::second; //== 2
constexpr static const int DVALUE1 = MagicStruct<3>::injected; // == 5
constexpr static const int DVALUE2 = MagicStruct<DVALUE1>::injected; // == 7
constexpr static const int DVALUE3 = MagicStruct<DVALUE2>::injected; // == 9
int main(int n, char* args[])
{
std::cout << CVALUE1 << std::endl;
std::cout << CVALUE2 << std::endl;
std::cout << DVALUE1 << std::endl;
std::cout << DVALUE2 << std::endl;
std::cout << DVALUE3 << std::endl;
return 0;
}
您可以将 injected
改为 static int
:
template<int A>
struct MagicStruct
{
enum { current = A };
static int injected;
};
template<int A>
int MagicStruct<A>::injected;
然后给InjectionStruct
一个静态成员,其实例化将填充MagicStruct<A>::injected
:
template<int A, int B>
struct InjectionStruct : MagicStruct<A>
{
enum { first=A, second=B};
struct filler {
filler() { MagicStruct<A>::injected = B; }
};
static filler inject;
};
template <int A, int B>
typename InjectionStruct<A,B>::filler InjectionStruct<A,B>::inject;
然后要进行注入,你只需要在某处使用inject
,或者显式实例化它:
static const int AVALUE = 1;
static const int BVALUE = 2;
static const int CVALUE = InjectionStruct<AVALUE, BVALUE>::first; //== 1
static const int DVALUE = InjectionStruct<AVALUE, BVALUE>::second; //== 2
//explicit instantiation
template InjectionStruct<AVALUE,BVALUE>::filler
InjectionStruct<AVALUE,BVALUE>::inject;
static const int EVALUE = MagicStruct<AVALUE>::injected; //== 2
或者,您可以在用于检索 first
或 second
.
的某些函数中隐藏 injected
的实例化
这是一个疯狂的实现,它依赖于通过模板实例化注入函数的实现。如果它没有正确实现相关的标准规则,这可能不适用于您的编译器,但它仍然很有趣,并且在编译时完全透明地工作:
template<typename>struct Type{};
template<int A>
struct MagicStruct
{
friend constexpr int get_injected(Type<MagicStruct<A>>);
static constexpr int current() { return A; }
template <int V = get_injected(Type<MagicStruct<A>>{})>
static constexpr int injected() { return V; }
};
template<int A, int B>
struct InjectionStruct
{
static constexpr int first() { return A; }
static constexpr int second() { return B; }
friend constexpr int get_injected(Type<MagicStruct<A>>) { return B; }
};
您对此实现的使用几乎完全符合您的要求:
static const int AVALUE = 1;
static const int BVALUE = 2;
static const int CVALUE = InjectionStruct<AVALUE, BVALUE>::first(); //== 1
static const int DVALUE = InjectionStruct<AVALUE, BVALUE>::second(); //== 2
static const int EVALUE = MagicStruct<AVALUE>::injected(); //== 2
我想我问的不可能,但我想完全确定,所以我还是问了..
我想从未在模板中传递但以其他方式注入的模板化结构(可用于 constexpr 函数)中获取编译时值。
很难解释,我会尝试一些代码:
template<int A>
struct MagicStruct
{
enum { current = A, injected = /* magic */}
};
template<int A, int B>
struct InjectionStruct
{
enum { first=A, second=B}
/*... injection of B in MagicStruct<A> ... */
};
static const int AVALUE = 1;
static const int BVALUE = 2;
static const int CVALUE = InjectionStruct<AVALUE, BVALUE>::first; //== 1
static const int CVALUE = InjectionStruct<AVALUE, BVALUE>::second; //== 2
static const int DVALUE = MagicStruct<AVALUE>::injection; //== 2
是否有一些我不知道的技巧允许这样做?
[编辑] 我想在输入中使用 AVALUE 作为模板参数来获取 DVALUE
以下内容对您有帮助吗?
template<int A, int B>
struct InjectionStruct
{
constexpr static int first = A;
constexpr static int second = B;
constexpr static int MAGIC = B;
};
template<int A, class Injection>
struct MagicStruct
{
constexpr static int current = A;
constexpr static auto injected = Injection::MAGIC;
};
static const int AVALUE = 1;
static const int BVALUE = 2;
static const int CVALUE = InjectionStruct<AVALUE, BVALUE>::first; //== 1
static const int CVALUE = InjectionStruct<AVALUE, BVALUE>::second; //== 2
static const int DVALUE = MagicStruct<AVALUE, InjectionStruct<AVALUE, BVALUE>>::injected; //== 2
很难给出更深入的建议,不知道你想注入什么。
您需要 InjectionStruct
和 MagicStruct
之间的某种关系。出于这个原因,我为 injected
值和 InjectionStruct
中的 typdef
添加了一个额外的模板参数。
第一个例子使用InjectionStruct
本身来定义具体的MagicStruct:
示例:
// MagicStruct is generic
template<int A, int INJ>
struct MagicStruct
{
enum { current = A, injected = INJ};
};
// Injection struct has it own copy of MagicStruct
template<int A, int B>
struct InjectionStruct
{
enum { first=A, second=B};
// Provide custom magic number
constexpr static int provideInjection(){ return B;}
// Own copy of magicStruct, injected by this template instance.
template <int X> struct MagicStruct: public ::MagicStruct<X,provideInjection()>{};
};
constexpr static const int AVALUE = 1;
constexpr static const int BVALUE = 2;
constexpr static const int CVALUE1 = InjectionStruct<AVALUE, BVALUE>::first; //== 1
constexpr static const int CVALUE2 = InjectionStruct<AVALUE, BVALUE>::second; //== 2
// Using a specific InjectionStruct, provies the MagicStruct with one argument.
constexpr static const int DVALUE3 = InjectionStruct<AVALUE, BVALUE>::MagicStruct<AVALUE>::injected; //== 2
int main()
{
std::cout << CVALUE1 << std::endl;
std::cout << CVALUE2 << std::endl;
std::cout << DVALUE3 << std::endl;
return 0;
}
在下面的解决方案中,MagicStruct
从默认值 InjectionStruct
中获取魔法值,即修复。
// InjectionStruct is generic.
template<int A, int B>
struct InjectionStruct
{
enum { first=A, second=B};
constexpr static int provideInjection(){ return A+B;}
};
constexpr static const int AVALUE = 1;
constexpr static const int BVALUE = 2;
// Define MagicStruct based on a specific InjectionStruct
template<int A, int INJ = InjectionStruct<A,BVALUE>::provideInjection()>
struct MagicStruct
{
enum { current = A, injected = INJ};
};
constexpr static const int CVALUE1 = InjectionStruct<AVALUE, BVALUE>::first; //== 1
constexpr static const int CVALUE2 = InjectionStruct<AVALUE, BVALUE>::second; //== 2
constexpr static const int DVALUE1 = MagicStruct<3>::injected; // == 5
constexpr static const int DVALUE2 = MagicStruct<DVALUE1>::injected; // == 7
constexpr static const int DVALUE3 = MagicStruct<DVALUE2>::injected; // == 9
int main(int n, char* args[])
{
std::cout << CVALUE1 << std::endl;
std::cout << CVALUE2 << std::endl;
std::cout << DVALUE1 << std::endl;
std::cout << DVALUE2 << std::endl;
std::cout << DVALUE3 << std::endl;
return 0;
}
您可以将 injected
改为 static int
:
template<int A>
struct MagicStruct
{
enum { current = A };
static int injected;
};
template<int A>
int MagicStruct<A>::injected;
然后给InjectionStruct
一个静态成员,其实例化将填充MagicStruct<A>::injected
:
template<int A, int B>
struct InjectionStruct : MagicStruct<A>
{
enum { first=A, second=B};
struct filler {
filler() { MagicStruct<A>::injected = B; }
};
static filler inject;
};
template <int A, int B>
typename InjectionStruct<A,B>::filler InjectionStruct<A,B>::inject;
然后要进行注入,你只需要在某处使用inject
,或者显式实例化它:
static const int AVALUE = 1;
static const int BVALUE = 2;
static const int CVALUE = InjectionStruct<AVALUE, BVALUE>::first; //== 1
static const int DVALUE = InjectionStruct<AVALUE, BVALUE>::second; //== 2
//explicit instantiation
template InjectionStruct<AVALUE,BVALUE>::filler
InjectionStruct<AVALUE,BVALUE>::inject;
static const int EVALUE = MagicStruct<AVALUE>::injected; //== 2
或者,您可以在用于检索 first
或 second
.
injected
的实例化
这是一个疯狂的实现,它依赖于通过模板实例化注入函数的实现。如果它没有正确实现相关的标准规则,这可能不适用于您的编译器,但它仍然很有趣,并且在编译时完全透明地工作:
template<typename>struct Type{};
template<int A>
struct MagicStruct
{
friend constexpr int get_injected(Type<MagicStruct<A>>);
static constexpr int current() { return A; }
template <int V = get_injected(Type<MagicStruct<A>>{})>
static constexpr int injected() { return V; }
};
template<int A, int B>
struct InjectionStruct
{
static constexpr int first() { return A; }
static constexpr int second() { return B; }
friend constexpr int get_injected(Type<MagicStruct<A>>) { return B; }
};
您对此实现的使用几乎完全符合您的要求:
static const int AVALUE = 1;
static const int BVALUE = 2;
static const int CVALUE = InjectionStruct<AVALUE, BVALUE>::first(); //== 1
static const int DVALUE = InjectionStruct<AVALUE, BVALUE>::second(); //== 2
static const int EVALUE = MagicStruct<AVALUE>::injected(); //== 2