模板非类型模板化参考参数

时间:2014-03-15 03:09:18

标签: c++ templates template-meta-programming

我有一系列模板化的类,我希望在编译时相互了解。每个对象可能具有其他编译时属性,这些属性将用于设置代码的运行时条件。

我理想的模式是这样的:

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 >

但是这需要我传递两个额外的参数(而不是让编译器推断它们)并且不能很好地扩展。

谢谢!

2 个答案:

答案 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_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);
}

在你的功能中:

FirstClass<1,2> fc;
auto sc = secondClass(fc)