以下代码无法编译。正确的语法是什么?它可用吗?
我让
struct overloaded
继承其转换后的模板参数,将每个参数包装到 can_convert<T>
中,然后将其用作 overloaded
的基类。现在,我想让所有 operator T()
在重载中可用,因此需要使用声明性的可变参数。这就是我不知道这在 C++ 中是否可行的地方,如果可以,语法应该是什么样子。
#include <string>
template <typename T>
struct can_convert_to
{
using type = T;
operator T();
};
template<class... Ts>
struct overloaded : can_convert_to<Ts>... {
// WHAT WOULD BE THE CORRECT SYNTAX HERE?
using can_convert_to<Ts>::operator typename can_convert_to<Ts>::type()...;
};
template<typename... Ts>
auto any_of() {
overloaded<Ts...> o;
return o;
};
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>);
只需删除
can_convert_to<Ts>::type
后面的括号,因为语法是:
使用 类型名称(可选) 嵌套名称说明符 不合格的id ;
如https://en.cppreference.com/w/cpp/language/using_declaration中所述。 nested-name-specifier 是一个“名称和作用域解析运算符 :: 的序列,以作用域解析运算符结尾”,指定要在其中查询 id 的命名空间,而 unqualified-id 基本上是指定您想要引入的名称的裸标识符。 using 声明并不真正关心实际的函数签名,所有重载都被引入。
template <class... Ts>
struct overloaded : can_convert_to<Ts>... {
using can_convert_to<Ts>::operator typename can_convert_to<Ts>::type...;
};
https://godbolt.org/z/Td7sxE6YT
并且,您可能已经注意到此代码仍然无法编译,因为关于 L34 上的
static_assert
的 Bar
失败了。如果你研究一下原因,你会发现“对成员函数'set'的调用是不明确的”。实现 has_set
的“更正确”方法如下:
#include <string>
template <typename T, typename... Args>
concept has_set_args = ((requires(T t, Args args) {
{ t.set(args) } -> std::same_as<void>;
}) || ... || false);
// Assume you only want the string-like ones
template <typename T>
concept has_set = has_set_args<T, std::string_view, std::string, const char *>;
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>);
has_set_args
检查所有类型以查看其中是否有任何类型可以用作 set
中的参数。另外,您可能只想提供 has_set
与 std::string_view
和 char*
,因为 std::string
可以隐式转换为 std::string_view
。