C++模板函数中调用std::string的c_str()为何触发编译错误?
问题原因
这是C++模板的常规语法规则导致的:
- 普通的
if分支哪怕判断条件是编译期常量,模板实例化的时候也会检查所有分支的语法合法性,不会因为某个分支逻辑上永远走不到就跳过语法检查。你用double作为T实例化模板的时候,整个函数体所有代码都会被校验,那行value.c_str()自然会因为double类型没有c_str成员报错。 std::is_same的返回值确实是编译期常量,但普通if没有“丢弃不匹配分支”的语义,这个语义是C++17才新增的if constexpr具备的特性。
解决方案
方案1:C++17及以上标准,用if constexpr替换所有普通if
把模板函数里的普通if都换成if constexpr即可,修改后代码如下:
template<typename T> int function(T value){ if constexpr(std::is_same<T,double>() || std::is_same<T,float>()){ std::cout << value << ", type is float" << std::endl; return 0; } else if constexpr(std::is_same<T,std::string>()){ std::cout << value.c_str() << ", type is string" << std::endl; return 0; } else if constexpr(std::is_same<T,char*>() || std::is_same<T,const char*>()){ std::cout << value << ", type is char*" << std::endl; return 0; } else{ std::cout << "Unsupported data type" << std::endl; return -1; } }
if constexpr会在编译期就把不匹配的分支直接丢弃,不会对丢弃的分支做语法检查,所以非std::string类型实例化的时候,c_str()那行代码根本不会被编译器处理,自然不会报错。
方案2:兼容旧C++标准,用模板重载/特化实现
如果不能使用C++17,可以把不同类型的处理逻辑拆分到不同的重载函数里:
// 处理浮点类型 int function_impl(double value) { std::cout << value << ", type is float" << std::endl; return 0; } int function_impl(float value) { std::cout << value << ", type is float" << std::endl; return 0; } // 处理string类型 int function_impl(const std::string& value) { std::cout << value.c_str() << ", type is string" << std::endl; return 0; } // 处理char*类型 int function_impl(const char* value) { std::cout << value << ", type is char*" << std::endl; return 0; } int function_impl(char* value) { std::cout << value << ", type is char*" << std::endl; return 0; } // 兜底不支持的类型 template<typename T> int function_impl(T) { std::cout << "Unsupported data type" << std::endl; return -1; } template<typename T> int function(T value) { return function_impl(value); }
该写法在C++11甚至更早的标准下都可以正常编译运行。
内容的提问来源于stack exchange,提问作者LoW
相关产品推荐
相关产品推荐

