我有一系列模板化的类,我希望在编译时相互了解。每个对象可能具有其他编译时属性,这些属性将用于设置代码的运行时条件。
我理想的模式是这样的:
template <unsigned int A, unsigned int B>
class FirstClass
{
};
template < template<unsigned int A, unsigned int B> FirstClass &firstClass >
class SecondClass
{
};
//...
FirstClass<1,2> fc;
SecondClass<fc> sc;
ThirdClass<sc> tc;
//...
有办法做到这一点吗?
如果我为SecondClass执行类似的操作,我可以接近:
template < unsigned int A, unsigned int B, FirstClass<A,B> &firstClass >
但是这需要我传递两个额外的参数(而不是让编译器推断它们)并且不能很好地扩展。
谢谢!
答案 0 :(得分:0)
我认为C ++ 11的decltype是你正在寻找的。它会让你不要一遍又一遍地写这些模板参数。
值得注意的是,在下面的示例中,SecondClass中的指针代码完全没必要,我只包含它,因为我不确定您的项目是否需要运行时访问权限。 ThirdClass是首选示例。
编辑:我阅读了关于任意数量类型的评论。这里的FourthClass或FifthClass可能是您正在寻找的东西。它使用可变参数模板,元组和一些TMP代码(for_each迭代一个元组)来自问题https://stackoverflow.com/users/680359/emsr中的iterate over tuple。我希望这里有足够的东西让你入门。
#include<iostream>
#include<tuple>
#include<string>
template <unsigned int A, unsigned int B>
struct FirstClass
{
static constexpr unsigned int C = A;
static constexpr unsigned int D = B;
};
template < typename T, const T* const t >
struct SecondClass
{
static constexpr unsigned int FOR_THIRD_CLASS = T::C;
//SecondClass knows about a FirstClass instance at compile time
static constexpr T* const pFirstClass = t;
//uses FirstClass values, which were computed at compile time, at runtime
void printFirstClassValues() const {
//ThirdClass below is an example without pointers or references, which it sounds like you don't need
std::cout << t -> C << " " << t -> D;
}
};
template < typename T >
struct ThirdClass
{
void printSecondClassValue() const {
std::cout << "\nIn ThirdClass method: " << T::FOR_THIRD_CLASS;
}
};
static constexpr FirstClass<1,2> fc;
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
for_each(std::tuple<Tp...> &, FuncT) // Unused arguments are given no names.
{ }
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
for_each(std::tuple<Tp...>& t, FuncT f)
{
f(std::get<I>(t));
for_each<I + 1, FuncT, Tp...>(t, f);
}
struct Functor
{
template<typename T>
void operator()(T& t) const { std::cout << t << ", "; }
};
template< typename... Ts >
struct FourthClass{
std::tuple< Ts... > myTuple;
//if you need it...
static constexpr int numberOfTypes = sizeof...(Ts);
FourthClass(Ts... pack):myTuple(pack...){
}
void print(){
for_each( myTuple, Functor() );
}
};
//maybe this is better - give it a tuple to begin with
template < typename my_tuple >
class FifthClass{
};
//just use your imagination here - these are ridiculous typedefs that don't ever make sense to use, I'm just showing you how to use FifthClass with a variable number of types
typedef SecondClass< decltype(fc), &fc > SC;
typedef ThirdClass<SC> TC;
typedef FourthClass<TC> FC;
typedef std::tuple<SC,TC,FC> ArbitraryClasses;
typedef std::tuple<SC,TC,FC,ArbitraryClasses> OtherArbitraryClasses;
typedef std::tuple<SC,TC,FC,ArbitraryClasses,OtherArbitraryClasses, int, std::string> MoreArbitraryClasses;
int main(){
SecondClass<decltype(fc), &fc> sc;
ThirdClass<decltype(sc)> tc;
sc.printFirstClassValues();
tc.printSecondClassValue();
std::cout << "\nEdit: here's a variadic example..." << std::endl;
FourthClass < int,unsigned int, short, const char*, int*, std::string > fourth(9,6,19,"this is a string", (int*)0xDEADBEEF, "I could keep going with any cout-able types");
fourth.print();
FifthClass < MoreArbitraryClasses > fifth;
return 0;
}
答案 1 :(得分:0)
正确的问题是:你真的关心第二个模板的参数是否真的来自第一个模板,或者如果它的行为与第一个模板完全相同,那么它是否合适?
在第二种情况下,实际上没什么可做的。只需使用普通的模板参数。
在第一种情况下,您始终可以将static_assert
与is_same
一起使用。它需要第一个类型具有两个参数的常量:
template <unsigned int A, unsigned int B>
class FirstClass
{
public:
constexpr static unsigned int a = A;
constexpr static unsigned int b = B;
};
然后你可以这样做:
template <typename FC>
class SecondClass
{
static_assert(std::is_same<FC,FirstClass<FC::a, FC::b> >::value, "Wrong template argument for SecondClass");
};
如果您不使用C ++ 11,请查看Boost中的static_assert实现,它并不复杂。你还必须自己实现is_same
,但我不知道这很难。
使用它:
FirstClass<1,2> fc;
SecondClass<decltype(fc)> sc;
请注意,永远不会允许在模板参数中使用局部变量。
您可能想要查看的另一件事(仍然是C ++ 11)是辅助函数:
如果你重写第二节课:
template <unsigned int A, unsigned int B>
struct SecondClass
{
FirstClass<A,B> fc;
A(FirstClass<A,B> arg)
:fc(arg)
{ }
};
然后你可以写:
template <unsigned int A, unsigned int B>
SecondClass<A,B> secondClass(FirstClass<A,B> arg)
{
return SecondClass<A,B>(arg);
}
在你的功能中:
FirstClass<1,2> fc;
auto sc = secondClass(fc)