【问题标题】:c++ templates overloading method depend on class typec ++模板重载方法取决于类类型
【发布时间】:2019-12-04 15:27:48
【问题描述】:

我有这样的课:

template<typename T>
MyClass{
   //myFunc();
}

我想创建 myFunc 方法,如果类模板是数字则返回数值,而当类模板不是数字时不返回任何内容 (void)。

现在,我得到了这样的东西:

template<typename T>
MyClass{
   template <typename returnT>
   returnT myFunc();
}


template <typename T>
template <typename returnT>
typename std::enable_if<std::is_arithmetic<T>::value>
T MyClass<T>::myFunc()
{
    return T::value;
}

template <typename T>
template <typename returnT>
typename std::enable_if<!std::is_arithmetic<T>::value>
void MyClass::myFunc()
{
    //do sth
}

当然,这是行不通的。以这种方式解决这个问题是个好主意吗?什么是“智能”且有效的解决方案?

【问题讨论】:

  • 视情况而定,两个版本的功能会不会相差很大?如果您可以使用c++17if constexpr 可能是一个不错的选择。
  • 另外,在需要重载函数的函数中使用 SFINAE。这意味着您需要在课堂上使用两个版本的 myFunc 才能正常工作。

标签: c++ templates metaprogramming template-meta-programming


【解决方案1】:

作为已经提供的constexpr if 解决方案的替代方案,以下是您的初步想法。

#include <type_traits>
#include <iostream>

template<typename T>
struct MyClass{
   template <typename returnT = T, std::enable_if_t<std::is_arithmetic_v<returnT>, bool> = true>
   T myFunc();

   template <typename returnT = T, std::enable_if_t<!std::is_arithmetic_v<returnT>, bool> = true>
   void myFunc();
};


template <typename T>
template <typename returnT, std::enable_if_t<std::is_arithmetic_v<returnT>, bool>>
T MyClass<T>::myFunc()
{
    std::cout << "yo\n";
    return T{};
}

template <typename T>
template <typename returnT, std::enable_if_t<!std::is_arithmetic_v<returnT>, bool>>
void MyClass<T>::myFunc()
{
    std::cout << "yay\n";
}

int main() {
    MyClass<int> m;
    MyClass<std::string> n;
    m.myFunc();
    n.myFunc();
}

【讨论】:

  • 谢谢。如果我想使用这个函数,比如:m.myFunc&lt;myType&gt;():,然后在 myFunc:return myType::someAtr 我认为在 myFuction 之上再增加一个 template 就足够了,但它不是 :(
  • @ziyiyituxe m.myFunc&lt;myType&gt; 将到达yay 分支,因为myType 不是算术。我不完全明白你的意思。
  • 您是否希望 MyClass&lt;int&gt; 始终返回 int,即使它像 MyClass&lt;int&gt;::myFunc&lt;myType&gt;(); 一样使用?
  • 我的意思是,我希望 myFunc 采用 myType 类型名,然后,如果 MyClass 是数字 return myType::someAtr;,如果不是:cout&lt;&lt;"Not numeric";
  • 可以的。如果你需要所有的组合来工作,你需要继续添加更多的重载。无论哪种方式,如果您提出一个新问题可能会更好,如果您想要一个不同的答案而不是修改它,请更具体。
【解决方案2】:

我能想到的最简单的方法就是使用if constexpr

template <typename T>
class MyClass
{
    auto myFunc()
    {
        if constexpr (std::is_arithmetic_v<T>)
        {
            return T{};
        }
        else
        {
            // do smth
        }
    }
};

如果你不能使用 C++17,你将不得不恢复到一些基于 SFINAE 的方法。最好的外观在很大程度上取决于所涉及的实际签名应该是什么。但是,例如,您可以为算术类型的情况提供部分类模板特化:

template <typename T, typename = void>
class MyClass
{
    void myFunc()
    {
        // do smth
    }
};

template <typename T>
class MyClass<T, std::enable_if_t<std::is_arithmetic<T>::value>>
{
    T myFunc()
    {
        return {};
    }
};

请注意,算术类型不能是类类型或枚举,因此对于 T 是算术类型的情况,我不确定 T::value 在您的示例代码中试图实现什么......

【讨论】:

    【解决方案3】:

    我会创建一个辅助模板类来选择返回类型,以及一个使用重载来执行正确行为的辅助函数。

    template <typename, bool> struct RType;
    template <typename T> struct RType<T, false> { typedef void type; };
    template <typename T> struct RType<T, true> { typedef T type; };
    
    template<typename T>
    class MyClass{
        typedef RType<T, std::is_arithmetic<T>::value> R;
    
        void myFuncT(RType<T, false>) {}
        T myFuncT(RType<T, true>) { return 0; }
    
    public:
        typename R::type myFunc() { return myFuncT(R()); }
    };
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-02
    • 2021-10-01
    • 1970-01-01
    • 2011-01-24
    • 2022-01-09
    • 1970-01-01
    • 2017-04-18
    • 1970-01-01
    相关资源
    最近更新 更多