2

我目前正在使用templateC++ 中的 s 并被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 classlikeMyHub接受一个实现MyInterface并提供某些static方法来使用它们,比如static T Foo().

然后我尝试使用MyHub

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

    return 0;
}

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

我希望它有效,因为

  • 模板参数的模板参数Impl命名为T
  • MyHub是具有一个模板参数并包含一个方法的模板类Foo

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

4

4 回答 4

5

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

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

是一个例子。

于 2015-09-03T10:24:53.133 回答
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();
}
于 2015-09-03T10:28:23.357 回答
3

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

您可以将MyInterface,MyImplMyHub类更改为:

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

于 2015-09-03T10:35:56.443 回答
2

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

这是有充分理由的:在包含的模板中没有什么可以引用的。当您有模板模板参数时,您必须将模板作为参数传递给它,而不是模板的实例化。换句话说,您正在传递一个没有参数的模板作为参数。

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

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

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

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

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;
}
于 2015-09-03T10:33:34.657 回答