C++可变using声明引入基类转换运算符:语法与可行性
可变参数using声明引入基类转换运算符的正确语法
问题描述
我定义了struct overloaded,让它继承多个can_convert_to<T>模板实例(每个模板参数Ts都被包装成can_convert_to<Ts>作为基类)。现在想把所有基类的operator T()转换运算符都引入到overloaded中,尝试用可变参数的using声明但语法错误,请问这个特性在C++中是否可行?正确语法是什么?
原代码中的错误关键行:
using can_convert_to<Ts>::operator typename can_convert_to<Ts>::type()...;
解答
这个特性在C++17及以后完全可行,正确的using声明语法需要简化:因为can_convert_to<T>中的转换运算符就是operator T(),而Ts本身就是can_convert_to<Ts>::type的别名,所以直接引用基类的operator Ts即可,不需要额外的typename和()。
修正后的核心代码行
using can_convert_to<Ts>::operator Ts...;
语法说明
- 转换运算符的using声明语法为
using BaseClass::operator TargetType;,末尾不需要加(),这是原代码的核心语法错误。 - C++17支持可变参数的using声明展开,能一次性将所有基类的对应转换运算符引入到派生类作用域中,解决基类成员名称隐藏的问题。
完整修正代码
#include <string> #include <concepts> // 需包含此头文件以使用std::same_as template <typename T> struct can_convert_to { using type = T; operator T(); // 概念检查仅需声明,无需定义 }; template<class... Ts> struct overloaded : can_convert_to<Ts>... { // 修正后的可变参数using声明 using can_convert_to<Ts>::operator Ts...; }; template<typename... Ts> auto any_of() { return overloaded<Ts...>{}; }; template<typename T> concept has_set = requires(T t) { { t.set(any_of<std::string_view, std::string, char*>()) } -> std::same_as<void>; }; struct Foo {}; static_assert(!has_set<Foo>); struct Bar { void set(std::string_view); void set(std::string); }; static_assert(has_set<Bar>); struct Baz { void set(std::string); }; static_assert(has_set<Baz>); struct Bazz { void set(char const *); }; static_assert(has_set<Bazz>); // char*可隐式转换为const char*,断言成立
补充说明
- 原代码遗漏了
<concepts>头文件,std::same_as依赖此头文件支持。 can_convert_to<T>::operator T()仅需声明无需定义,因为概念检查是编译期行为,不会实际调用该运算符。Bazz的set接受const char*,而any_of提供的char*可隐式转换为const char*,因此对应的静态断言能够成立。
内容的提问来源于stack exchange,提问作者Markus W.
相关产品推荐
相关产品推荐

