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

C++ conditionally call functions based on type of the template parameter

本文关键字:有条件 类型 调用 函数 参数 C++      更新时间:2024-09-23

假设我有几个函数来处理不同类型的参数。例如,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代码之间的差异将是一行。

对于这样的事情,我会建议模板和专业化:

// 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);
}

可选的普通旧重载也应该正常工作。

所有分支都应该有效,即使分支未被占用。 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{};
}

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

演示