模板非类型模板化引用参数
Template non-type templated reference parameter
我有一系列模板化的类,我想在编译时让它们相互知道。每个对象可能有其他编译时属性,这些属性将用于为代码设置运行时条件。
我的理想模式是这样的:
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 >
但是这需要我传递两个额外的参数(而不是让编译器推断它们),并且不会很好地扩展。
谢谢!
正确的问题是:您是否真的关心第二个模板的参数是否真的来自第一个模板,或者如果它的行为与第一个模板完全相同,您是否可以接受?
在第二种情况下,真的没什么可做的。只需使用普通模板参数。
在第一种情况下,您总是可以使用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);
}
And in you function:
FirstClass<1,2> fc;
auto sc = secondClass(fc)
我认为c++ 11的decltype是你正在寻找的。它可以让你避免一遍又一遍地写这些模板参数。
需要注意的是,在下面的例子中,SecondClass中的指针代码是完全没有必要的,我包含它只是因为我不确定你的项目是否需要运行时访问。ThirdClass是首选的示例。
编辑:我读了你关于任意数量的类型的评论。四等或五等车厢可能就是你要找的。它使用可变的模板、元组和一些TMP代码(for_each迭代元组),这些代码来自https://stackoverflow.com/users/680359/emsr。我希望这里有足够的东西让你开始。
#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;
}
相关文章:
- 将const引用参数初始化为默认参数会导致悬空引用吗
- 具有常量引用参数的函数模板专用化
- C++:常量引用参数
- 字符串引用参数的效率C++
- 通过非常量引用参数修改常量引用参数
- 如何将指针变量作为引用参数传递?
- C++初始化 std::function 时如何将占位符绑定到引用/引用参数?
- 移动类的成员作为常量引用参数传递
- C++带有适用于左值和右值的引用参数的函数
- constexpr 函数的常量引用参数:gcc/msvc vs clang/icc
- 如何使用类型特征将函数的通用引用参数限制为 r 值引用?
- 委托构造函数和引用参数
- 对 const 引用参数使用默认值会导致崩溃
- 为什么我们不允许将纯引用参数传递给 std::thread,但允许传递原始指针?
- 为什么我需要将默认引用参数定义为 const 以便为其分配一个左值?
- 将非左值作为常量引用参数传递.临时是在本地作用域还是在调用方作用域中创建的?
- 如何强制函数仅接受左值引用参数
- 模板引用参数推断失败C++
- 非类型引用参数可以在运行时修改,这是否意味着模板可以在运行时实例化?
- 将unique_ptr作为引用参数或常量传递unique_ptr引用