模板非类型模板化引用参数

Template non-type templated reference parameter

本文关键字:引用 参数 类型      更新时间:2023-10-16

我有一系列模板化的类,我想在编译时让它们相互知道。每个对象可能有其他编译时属性,这些属性将用于为代码设置运行时条件。

我的理想模式是这样的:

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_assertis_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;
}