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

Use template parameter of template template parameter

我目前正在使用 C++ 中的 templates 并卡在 template template parameters.

假设我有以下 classes:

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() { }
};

本质上我想要一个像 MyHub 这样的 static class 接受 MyInterface 的实现并提供某些 static 方法来使用它们 [=18] =].

然后我尝试使用 MyHub:

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

    return 0;
}

不幸的是,我总是得到一个错误,说类型 T(属于 MyHub 中的 static T Foo())没有命名类型。

我希望它能起作用,因为

到目前为止,我在查阅文档和 google 结果后找不到解决方案,所以我希望你们中的一些人能帮助我。

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

#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就是一个例子。

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

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();
}

模板模板参数的模板参数名称实际上是一个纯粹的文档结构——它们不包含在包含模板的范围内。

这是有充分理由的:在包含的模板中没有他们可以引用的内容。当你有模板模板参数时,你必须传递一个 template 作为参数给它,而不是模板的 instantiation。换句话说,您传递的模板 没有参数 作为参数。

这意味着您的代码完全错误——您使用 MyImpl 作为 MyHub 的参数,但 MyImplclass . MyHub 需要一个 模板, 而不是 class。 [=13 的正确实例化=] 将是 MyHub<MyInterface>。并不是说在使用 MyInterface 之后没有模板参数;我们传递的是模板本身,而不是它的实例。

Template 模板参数在实践中很少使用。仅当您想使用自己的类型实例化参数模板时才使用它们。所以我希望你的 MyHub 代码能做这样的事情:

template <template <class> class ImplTemplate>
struct MyHub
{
  typedef ImplTemplate<SomeMyHub_SpecificType> TheType;
  // ... use TheType
};

这似乎不是您想要的。我相信您需要一个普通类型模板参数,并为其 T 提供一个嵌套的 typedef。像这样:

template <class T>
struct MyInterface
{
  typedef T ParamType;  // Added

  virtual T Foo() = 0;
};


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

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

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

    return 0;
}

MyImpl 不是 class 模板;所以不能作为 MyInterface.

的模板参数传递

您可以将 MyInterfaceMyImplMyHub class 更改为:

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 派生的 class 方法 foo().