模板类带有模板成员

template class to class with template member

本文关键字:成员      更新时间:2023-10-16

类似这样的类模板

template <typename... T>
class Action {
private:        
    std::tuple<T...> m_args;
public:
    Action(T... args) : m_args(args...) {}
}

带有模板成员的课程。之所

class Action {
private:       
    // this does not work, how to declare the tuple type so that It can hold any arguments list.
    template <typename... T>
    std::tuple<T...> m_args;
public:   
    template <typename... T>
    Action(T... args) : m_args(args...) {}
}

将您的思想放在编译器的角度上。如果该尺寸取决于解决哪个构造函数,我们值得信赖的朋友如何知道Action需要多少存储空间?这是不可能的。

template<typename... T>
Action(T... args) : m_args(args...) {}
// wait what???
Action(int someArg) : m_args(someArg) {}

假设第二个构造函数是有效的,或者我们有两个Action对象,其中包含不同的参数传递到构造函数 - sizeof(Action)应该是什么?

什么?

如果您陷入了这样的问题,请将其作为编译器:可能有些人不得不给出足够的理由为什么不应该支持它,仅仅是因为它只会使实施变得复杂并具有绩效含义。


由于您提到了使用指针而不是聚合对象,所以我想我会向您展示如何进行完整性。请注意,这具有性能含义,因为您现在正在为堆上的m_args分配内存,而不是堆栈。

class Action
{
public:
    template<typename... T>
    using TArgs = std::tuple<T...>;
    std::shared_ptr<void> m_args;
    template<typename... T>
    Action(T... args) 
        : m_args(std::make_shared<TArgs<T...>>(args...)) {}
};
Action myAction(1, 2.0, 3.5f);
auto *myActionArgs = 
    static_cast<Action::TArgs<int, double, float>*>(myAction.m_args.get());
// 2.0
double secondArg = std::get<1>(*myActionArgs);

这看起来并不有趣。