【问题标题】:Template non-type templated reference parameter模板非类型模板化引用参数
【发布时间】:2014-03-15 03:09:18
【问题描述】:

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

我的理想模式是这样的:

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 >

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

谢谢!

【问题讨论】:

  • 你想用这台机器完成什么?您如何看待只有一个“特征”类可以作为 FirstClass 和 SecondClass 的模板参数传递?
  • @JohnZwinck 他仍然无法将实例(引用)作为模板参数传递。

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


【解决方案1】:

正确的问题是:您是否真的关心第二个模板的参数是否真的来自第一个模板,或者如果它的行为与第一个模板完全一样,您是否可以?

在第二种情况下,真的无事可做。只需使用普通模板参数。

在第一种情况下,您始终可以将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)

【讨论】:

    【解决方案2】:

    我认为 C++11 的 decltype 是您正在寻找的。它会让你避免一遍又一遍地编写那些模板参数。

    需要注意的是,在下面的示例中,SecondClass 中的指针代码是完全没有必要的,我之所以包含它只是因为我不确定您的项目是否需要运行时访问。 ThirdClass 是首选示例。

    编辑:我阅读了您关于任意数量类型的评论。此处的FourthClass 或FifthClass 可能是您正在寻找的。它使用来自https://stackoverflow.com/users/680359/emsr 有问题的iterate over tuple 的可变参数模板、元组和一些TMP 代码(for_each 迭代一个元组)。

    我希望这里有足够的内容可以帮助您入门。

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

    【讨论】:

    • 这似乎是在正确的方向。我可以看到的主要区别是我希望累积更改。我想我在原始帖子中没有说清楚,但我希望它可以与任意数量的类一起使用——在编译时已知,但使用的类可能因实现而异。例如,一个程序可能使用 First、Second 和 Fourth 类;另一个可能会使用 First、Fifth、Seventh 和 Ninth。
    • 什么意思? T 可以是任何东西,只要成员名称与模板中的用法相匹配。如果您希望将任意数量的类传递给单个模板,则可以将其设为可变参数模板。如果您需要运行时访问,您可以使用引用或指针(也可以是可变参数,这意味着您可以在运行时访问任意数量的对象。您能否解释得更清楚一点(在编译时知道什么?那东西需要同时知道任意数量的类吗?)?
    • 我继续在FourthClass 和FifthClass 中给出了一些在模板中具有任意数量类型的方法的示例。
    猜你喜欢
    • 1970-01-01
    • 2021-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多