当模板函数也匹配时,如何定义特殊的句柄函数?

nic*_*ick 1 c++ templates class member-functions c++11

我有一个带有模板函数和一个特殊函数的类,如下所示:

#include <bits/stdc++.h>
using namespace std;

class A
{ 
 public:
  template <typename T>
  void test(const T& t) 
  {
    cout << "template " << t << endl;
  }

  void test(const std::string& s) {
    cout << "test " << s << endl;
  }
};

int main() 
{
  A a;
  a.test("asdas");
}
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,有两个test函数:

  1. template功能
  2. 仅匹配输入的特殊函数std::string

我想要的是:

  1. test(1)-> 调用template函数test<int>(1)
  2. std::string str = "asd"; test(str);-> 调用特殊函数test(str)
  3. test("asd")-> 调用特殊函数test(std::string str = "asd")

如何实现这一目标?

JeJ*_*eJo 5

不是asdasstd::string而是可以称为 的字符串文字const char*。这就是为什么a.test("asd")没有给会员打电话void test(std::string const& s)


如何实现这一目标?

解决方法之一是再证明一个成员超载

class A 
{
public:
    // ... code
    void test(std::string const& s) {
        cout << "test " << s << endl;
    }

    void test(const char* s) {   // overload for string literals
        test(std::string{s});
    }
};

Run Code Online (Sandbox Code Playgroud)

查看演示

或者,在中,您可以SFINAE 这两个函数

class A
{
public:
    template <typename T>
    auto test(const T& t) // T can not be convertible to std::string
        -> typename std::enable_if<!std::is_convertible<T, std::string>::value>::type
    {
        std::cout << "template " << t << std::endl;
    }

    template<typename T>
    auto test(T const& s) // T can be convertible to std::string
        -> typename std::enable_if<std::is_convertible<T, std::string>::value>::type
    {
        std::cout << "test " << s << std::endl;
    }
};
Run Code Online (Sandbox Code Playgroud)

查看演示


但是,如果您至少能够升级到,则可以使用字符串文字,并将 传递std::stringvoid test(std::string const& s)(即不再需要成员重载)

using namespace std::string_literals;

a.test("asd"s);
//         ^^^
Run Code Online (Sandbox Code Playgroud)

查看演示


更进一步,在中,我们可以使用 来决定在编译时编译/丢弃条件的哪一部分if constexpr

class A 
{
public:
    template <typename T>
    void test(const T& t)
    {
        if constexpr (!std::is_convertible_v<T, std::string>)
        {
            std::cout << "template " << t << std::endl;
        }
        else
        {
            std::cout << "test " << t << std::endl;
        }
    }
};
Run Code Online (Sandbox Code Playgroud)

查看演示


另请阅读:

  • SFINAE 甚至可以在 C++11 之前完成。只是所提供的工具/特征(例如“std::enable_if”)需要重新实现。 (2认同)