使用模板模板参数的模板参数

时间:2015-09-03 10:17:15

标签: c++ templates c++17

我目前正在使用C ++中的template,并且遇到了template template parameters

假设我有以下课程:

template<typename T>
struct MyInterface
{
    virtual T Foo() = 0;
}

class MyImpl : public MyInterface<int>
{
public:
    int Foo() { /*...*/ }
};

template< template<typename T> typename ImplType>
class MyHub
{
public:
    static T Foo()
    {
        ImplType i;
        return i.Foo();
    }

private:
    MyHub() { }
    ~MyHub() { }
};

从本质上讲,我希望static class类似MyHub接受MyInterface的实施,并提供某些static方法来使用它们static T Foo()点。

然后我尝试使用MyHub

int main()
{
    int i = MyHub<MyImpl>::Foo();

    return 0;
}

不幸的是,我总是收到一条错误消息,指出T(MyHub中的static T Foo())类型没有命名类型。

我希望它有效,因为

  • 模板参数Impl的模板参数名为T
  • MyHub是带有一个模板参数的模板化类,包含方法Foo

到目前为止,我在挖掘文档和谷歌搜索结果后找不到解决方案,所以我希望你们中的一些人可以帮助我。

4 个答案:

答案 0 :(得分:5)

您可以使用typedef。此外,由于您的实现类不是模板类,因此不需要模板模板参数。

#include <iostream>
#include <string>

template<typename T>
struct MyInterface
{
    virtual T Foo() = 0;
    typedef T Type;
};

class MyIntImpl : public MyInterface<int>
{
public:
    int Foo() { return 2; }
};

class MyStringImpl : public MyInterface<std::string>
{
public:
    std::string Foo() { return "haha"; }
};

template<class ImplType>
class MyHub
{
public:
    static typename ImplType::Type Foo()
    {
        ImplType i;
        return i.Foo();
    }

private:
    MyHub() { }
    ~MyHub() { }
};

int main()
{
    std::cout << MyHub<MyIntImpl>::Foo() << "\n"; // prints 2
    std::cout << MyHub<MyStringImpl>::Foo() << "\n"; // print haha
    return 0;
}

Here就是一个例子。

答案 1 :(得分:3)

STL使用value_type作为模板类的基础类型的占位符。你可以为你的解决方案做同样的事情。

template<typename T>
struct MyInterface
{
    typedef T value_type;
    virtual T Foo() = 0;
}

class MyImpl : public MyInterface<int>
{
public:
    int Foo() { /*...*/ }
};

template<typename ImplType>
class MyHub
{
public:
    static typename ImplType::value_type Foo()
    {
        ImplType i;
        return i.Foo();
    }

private:
    MyHub() { }
    ~MyHub() { }
};

另请注意,在c ++ 14中,typename ImplType::value_type可以替换为auto

static auto Foo()
{
    ImplType i;
    return i.Foo();
}

答案 2 :(得分:3)

MyImpl不是类模板;因此无法作为MyInterface的模板参数传递。

您可以将MyInterfaceMyImplMyHub课程更改为:

template<typename T>
class MyInterface{
    public:
        virtual T foo() = 0;
};

class MyImpl: public MyInterface<int>{
    public:
        using value_type = int;

        value_type foo(){ return 1; /* dummy */ }
};

template<typename Impl, typename = std::enable_if_t<std::is_base_of<Impl, MyInterface<typename Impl::value_type>>::value>>
class MyHub{
    public:
        static auto foo(){
            static Impl i;
            return i.foo();
        }
};

让您以与示例相同的方式使用它。

在这种情况下,std::is_base_of检查可能有点不必要;但是,通过这种方式,您无法通过方法MyInterface意外传入另一个不是foo()的类。

答案 3 :(得分:2)

模板模板参数的模板参数名称实际上是纯粹的文档化构造 - 它们不会包含在包含模板的范围内。

这是有充分理由的:他们可以在包含模板中引用任何内容。如果有模板模板参数,则必须将模板作为参数传递给它,而不是模板的实例化。换句话说,您传递的模板没有参数作为参数。

这意味着您的代码完全错误 - 您使用MyImpl作为MyHub的参数,但MyImpl类。 {{1需要一个模板,而不是一个类。 MyHub的正确实例化将是MyHub。并非在使用MyHub<MyInterface>之后没有模板参数;我们传递模板本身,而不是它的实例化。

模板模板参数在实践中很少使用。如果要使用自己的类型实例化参数模板,则只能使用它们。所以我希望您的MyInterface代码可以执行以下操作:

MyHub

这似乎不是你想要做的。我相信你想要一个普通的类型模板参数,并为它的template <template <class> class ImplTemplate> struct MyHub { typedef ImplTemplate<SomeMyHub_SpecificType> TheType; // ... use TheType }; 提供一个嵌套的typedef。像这样:

T