3

所以我一直在尝试更多地理解可变参数模板,我的目标是接收所有类型,扩展它们并打印它们。我能够在一个函数中做到这一点(找到一些例子)但我不是能够为班级做到这一点我正在尝试构建一个“主人”来容纳许多“奴隶”,每个奴隶都应该从他那里继承一个 Slave_T 然后知道它的类型,并将其打印在 c'tor 上。

但由于某种原因,我无法修复模棱两可的编译错误。我试图避免将任何类型作为参数传递给函数。我尝试使用 enable_if 或 true/false_type 约定但无法,任何人都有任何想法? 这是我的代码:(包括功能扩展)

有效的功能扩展:

template<typename T, typename... Targs>
void Print(T value, Targs... Fargs) // recursive variadic function
{
    Print<T>();
    Print(Fargs...); // recursive call
}

template<typename T>
void Print(T = NULL)
{
    std::cout << typeid(T).name() << endl;
}

我需要帮助的类扩展:

#include <iostream>
#include <vector>
#include <type_traits>
#include <memory>
using namespace std;



struct Slave {
    virtual char const* Type() = 0;
};

template<typename T>
struct Slave_T : public Slave{
    virtual char const* Type() {
        return typeid(T).name();
    }
};

template <typename ...T>
struct Master {
    Master()
    {
        MakeSlave<T...>();
        cout << "All Slaves:" << endl;
        for (auto const& slave : v){
            cout << slave ->Type() << endl;
        }
    }
private:

    template<typename T, typename ...Rest>
    void MakeSlave()
    {
        MakeSlave<Rest...>(); MakeSlave<T>();
    }

    template<typename T>
    void MakeSlave()                    {
        v.push_back(new Slave_T<T>());
    }

    vector<shared_ptr<Slave>> v;
};

int main()
{
    Master<int, double, char> m;
    //Print("Hello", '!', 123, 123);
    return 0;
}

谢谢!

阿隆

4

1 回答 1

4

首先:为了允许多态模板,您定义了一个非模板化的纯虚拟基类Slave。您的模板类Slave_T必须继承自它(您想要一个std::vector包含异构模板,对吗?)。请注意,您使用的是基类定义的虚函数Slave。我想你之前忘记写基类列表了struct Slave_T:)

第二: 在虚函数的覆盖中Type(),你写Slave<T>::type的是Slave_T<T>::type. 另请注意,这句话typename之前需要关键字,因为是对依赖范围的引用。. 但是,另一方面,您可以访问Slave_T模板参数T,那么,为什么不简单地使用T?:)

第三:更喜欢使用std::make_shared而不是原始new句子。

第四:更喜欢std::string而不是 C 风格的原始字符串。

代码修复后编辑:

T私有函数的模板MakeSlave()参数隐藏类可变参数模板参数T。您必须使用其他名称。

顺便说一句,错误在于 makeslave 的重载是模棱两可的:您定义了一个带有模板参数T和可变参数的版本,即与可变参数包一起使用Params的典型HEAD TAIL递归方法。但是,另一方面,您还定义了一个只有一个模板参数的版本。请注意,这与第一个版本产生了歧义,因为可变参数包可以为空,因此在您的基本情况下,编译器不知道使用什么版本。

解决方案:

您可以使用 sentinel 类型来跟踪参数列表何时被完全处理。您使用此标记来启用/禁用基本情况以避免歧义:

template <typename ...T>
    struct Master {
        Master()
        {
            MakeSlave<T...,_my_centinel_type>();
            cout << "All Slaves:" << endl;
            for (auto const& slave : v){
                cout << slave ->Type() << endl;
            }
        }
    private:
        struct _my_centinel_type {};

        template<typename U, typename ...Rest>
        typename std::enable_if<!std::is_same<U,_my_centinel_type>::value , void>::type MakeSlave()
        {
                v.push_back( std::make_shared<Slave_T<U>>());
                MakeSlave<Rest...>();
        }

        template<typename U>
        typename std::enable_if<std::is_same<U,_my_centinel_type>::value , void>::type MakeSlave(){
            //The base case does anything
        }

在行动中看到它:http: //ideone.com/FqMPXh#

于 2013-08-03T10:04:48.337 回答