C++根据模板参数的类型有条件地调用函数[duplicate]

sigwle7e  于 2023-03-20  发布在  其他
关注(0)|答案(3)|浏览(148)

此问题在此处已有答案

Call function based on template argument type(7个答案)
7个月前关闭。
假设我有两个函数来处理不同类型的参数,例如processInt处理int变量,processString处理std::string变量。

int processInt(int i) 
{
    return i;
}

string processString(string s)
{
    return s;
}

我有一个叫foo的模板函数,它把intstd::string作为参数,在这个函数中,我需要根据发送给它的变量类型有条件地调用processIntprocessStringfoo函数如下所示:

#include <type_traits>

template<typename T>
T foo(T value)
{
    T variable;
    if (std::is_same<T, int>::value) 
    {
        variable = processInt(value); 
    }
    else if (std::is_same<T, string>::value)
    {
        variable = processString(value);
    }
    return variable;
}

int main() {
    string s = "Abc";
    int i = 123;
    cout << foo(s) << " " << foo(i) << endl;     
}

但是,使用上面的foo函数时,我得到了以下错误:

error: no matching function for call to 'processInt'
                variable = processInt(value); 
                           ^~~~~~~~~~
note: in instantiation of function template specialization 'foo<std::__cxx11::basic_string<char> >' requested here
    cout << foo(s) << " " << foo(i) << endl;    
            ^
note: candidate function not viable: no known conversion from 'std::__cxx11::basic_string<char>' to 'int' for 1st argument
int processInt(int i) 
    ^
error: no matching function for call to 'processString'
                variable = processString(value);
                           ^~~~~~~~~~~~~
note: in instantiation of function template specialization 'foo<int>' requested here
    cout << foo(s) << " " << foo(i) << endl;    
                             ^
note: candidate function not viable: no known conversion from 'int' to 'std::__cxx11::string' (aka 'basic_string<char>') for 1st argument
string processString(string s)
       ^

源代码:https://godbolt.org/z/qro8991ds
如何正确地根据泛型函数中模板参数的类型有条件地调用函数?

编辑

我喜欢使用一个foo函数,不需要重载或特殊化,否则可能会有一些代码重复。foo函数可能有很多行。但是,intstring的代码之间的差异只有一行。

epggiuax

epggiuax1#

对于这样的东西,我建议使用模板和专门化:

// Declare base template
template<typename T>
T process(T);

// Specialization for integers
template<>
int process(int value)
{
    // ... code to process integers...
}

// Specialization for strings
template<>
std::string process(std::string value)
{
    // ... code to process strings...
}

那么foo函数就变成了

template<typename T>
T foo(T value)
{
    return process(value);
}

可选地,普通的旧重载也应该可以工作。

ruarlubt

ruarlubt2#

所有的分支都应该是有效的,即使分支没有被执行。C++17有if constexpr可以解决你的问题

template<typename T>
T foo(T value)
{
    T variable;
    if constexpr (std::is_same<T, int>::value) 
    {
        variable = processInt(value); 
    }
    else if constexpr (std::is_same<T, string>::value)
    {
        variable = processString(value);
    }
    return variable;
}

对于c++17之前的版本,您可以使用重载来获得类似的结果(标记调度用于更复杂的情况):

int foo(int value)
{
    return processInt(value);
}

std::string foo(const std::string& value)
{
    return processString(value);
}

template <typename T
    // possibly some SFINAE to allow some conversion with above functions
    /*,  std::enable_if_t<std::is_constructible<std::string, T>, bool> = true */>
T foo(T value)
{
    return T{};
}
nfg76nw0

nfg76nw03#

在C++17中,您可以使用立即调用的lambda和if constexpr来完成此操作

template<typename T>
T foo(T value) {
  auto variable = [&value]{
    if constexpr (std::is_same_v<T, int>)
      return processInt(value);
    else if constexpr (std::is_same_v<T, std::string>)
      return processString(value);
  }();

  // use variable

  return variable;
}

Demo

相关问题