首页 > 解决方案 > 我可以在模板函数代码中使用 2 个不同的函数返回不同的数据类型吗?

问题描述

我正在尝试将我的一些代码模板化,但不确定我是否以正确的方式进行操作?

template <typename T>
class User
{
    public:
    template <typename T>
    void foo() {
A* pa = funcA();
        OR
        B* pb = funcB();
        //common code follows
         ....
         ....
         ....
};


User<Atype> C1;
User<Btype> C2;

在上面的代码中,我正在寻找如何定义 foo() 以便能够根据类的实例化方式使用 A* pa = funcA() 或 B* pb = funcB() 。C1 应该能够使用 A* pa = funcA(),C2 应该能够使用 B* pb = funcB()。

标签: c++11templates

解决方案


不是直接的,但有多种选择。通常最好避免导致需要不同命名函数或概念上不同操作的设计。

例如,如果 A 和 B 都有一个成员函数或静态函数foo,那么您可以调用它 ( x.foo(),T::foo()等) 而不是单独命名的funcAand funcB。或者类似地,在参数的情况下,您可以使用函数重载(因为您不能在返回类型上重载),例如std::to_string,有时还可以使用模板,例如std::swap.

否则,如果您需要支持完全不同的东西,那么有很多选择。

  1. 您可以专门foo为不同类型提供不同的实现。如果您计划在模板函数或类中使用许多不同的类型,这通常不是特别理想。在某些情况下,您可能会专攻整个班级,也有部分专业。

    class A {};
    class B {};
    
    A *funcA();
    B *funcB();
    
    template <typename T>
    class User
    {
    public:
        void foo();
    };
    
    template<> void User<A>::foo()
    {
        auto a = funcA();
        // ...
    }
    template<> void User<B>::foo()
    {
        auto ab = funcB();
        // ...
    }
    
  2. 与 1 类似,您可以拥有一个单独的模板函数或专门的类。

     class A {};
     class B {};
    
     A *funcA();
     B *funcB();
    
     template<class T> T *funcGeneric();
     template<> A *funcGeneric<A>() { return funcA(); }
     template<> B *funcGeneric<B>() { return funcB(); }
    
     template <typename T>
     class User
     {
      public:
         void foo()
         {
             auto p = funcGeneric<T>();
         }
     };
    

    或者使用一个类,如果您有多个方法或信息片段,这可能很有用。对于单个方法,调用运算符通常是重载的。

    template<class T> class FuncGeneric;
    template<> class FuncGeneric<A>
    {
    public:
        A *operator()()const { return funcA(); }
    };
    template<> class FuncGeneric<B>
    {
    public:
        B *operator()()const { return funcB(); }
    };
    
    template <typename T>
    class User
    {
    public:
        void foo()
        {
            auto p = FuncGeneric<T>()();
        }
    };
    
  3. 扩展 2,但您将“适配器”作为模板参数本身传递。这是你在 STL 中看到的一个相当多的东西,比如std::map获取Compare参数(默认std::less)、unique_ptr获取删除器(std::default_delete调用delete)、散列函数等。

    template<class T> class FuncGeneric;
    template<> class FuncGeneric<A>
    {
    public:
        A *operator()()const { return funcA(); }
    };
    template<> class FuncGeneric<B>
    {
    public:
        B *operator()()const { return funcB(); }
    };
    
    template <class T, class Func = FuncGeneric<T>>
    class User
    {
    public:
        void foo()
        {
            auto p = Func()();
        }
    };
    
  4. 在某些情况下,您可能会传递函数本身。对于函数而不是类来说更常见,例如许多算法(例如find_if)这样做。

    template <class T, class Func>
    class User
    {
    public:
        User(Func func) : func(func) {}
        void foo()
        {
            auto p = func();
        }
    private:
        Func func;
    };
    int main()
    {
        User<A, A*(*)()> user(&funcA);
    }
    
  5. 函数本身也可以是模板参数,尽管这种情况很少见。

    template <class T, T*(*Func)()>
    class User
    {
    public:
        void foo()
        {
            auto p = Func();
        }
    };
    int main()
    {
        User<A, &funcA> user;
    }
    

推荐阅读