使用转换运算符的声明式进行扩展

问题描述 投票:0回答:1

以下代码无法编译。正确的语法是什么?它可用吗?

我让

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>);
c++ operator-overloading variadic-templates
1个回答
0
投票

只需删除

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

© www.soinside.com 2019 - 2024. All rights reserved.