在名称空间下专门针对类型的访客

发布于 2025-01-22 22:00:23 字数 1189 浏览 0 评论 0原文

我有一个可以包含8种不同类型的变体,其中一些在特定的名称空间下

std::variant<T0, T1, T2, ns::T0, ns::T1, ns::T2> v;

存在一个免费功能,可以使用这些类型的任何类型调用,但是我正在访问这样的变体

int function(T0 t){return 0;}
int function(T1 t){return 1;}
int function(T2 t){return 2;}

namespace ns {
template <typename T>
int function(T t) {return 3;}
}

void doSomething() {
    std::visit([](const auto &t) {return function(t);}, v);
}

,但是现在我希望用户能够为了提供自己的访问者,并将其称为,如果提供的访问者与变体类型不匹配,请使用默认的访问者。为此,

int function(T0 t){return 0;}
int function(T1 t){return 1;}
int function(T2 t){return 2;}

namespace ns {
template <typename T>
int function(T t) {return 3;}
}

struct DefaultVisitor
{
    template <typename T>
    int operator()(T t) const {return function(t);}
}

template <typename VisitorT>
void doSomething() {
    std::visit(overloaded{VisitorT(), DefaultVisitor()}, v);
}

如果vistort提供一个类型的呼叫操作员, 我已经尝试了以下操作不编译。

我如何提供由ns名称空间中的类型使用的访问者,而不是其他类型的访问者?

https://godbolt.org/z/zv1o4nxne

I have a variant which can contain 8 different types, some of them under a particular namespace

std::variant<T0, T1, T2, ns::T0, ns::T1, ns::T2> v;

There exists a free function which can be called with any of these types and I am visiting the variant like this

int function(T0 t){return 0;}
int function(T1 t){return 1;}
int function(T2 t){return 2;}

namespace ns {
template <typename T>
int function(T t) {return 3;}
}

void doSomething() {
    std::visit([](const auto &t) {return function(t);}, v);
}

However, now I want the user to be able to provide his own visitor and call that, and in case, the provided visitor doesn't match for the variant type, use the default one. To do so I have tried the following

int function(T0 t){return 0;}
int function(T1 t){return 1;}
int function(T2 t){return 2;}

namespace ns {
template <typename T>
int function(T t) {return 3;}
}

struct DefaultVisitor
{
    template <typename T>
    int operator()(T t) const {return function(t);}
}

template <typename VisitorT>
void doSomething() {
    std::visit(overloaded{VisitorT(), DefaultVisitor()}, v);
}

If the VisitorT provides a call operator for only one type, this works fine, but if it provides a call operator for several types, such as a generic lambda, then it doesn't compile.

How could I provide a VisitorT which is used by the types in the ns namespace, but not for other types?

https://godbolt.org/z/zv1o4nxne

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

仅冇旳回忆 2025-01-29 22:00:23

您可以调整Overloaded具有一些优先级:

template <typename T1, typename... Ts>
struct ranked_overloaded : T1, ranked_overloaded<Ts...>
{
    template <typename... Us>
    auto operator()(Us&&... args)
    {
        if constexpr (requires{ T1::operator()(std::forward<Us>(args)...); }) {
            return T1::operator()(std::forward<Us>(args)...);
        } else {
            return ranked_overloaded<Ts...>::operator()(std::forward<Us>(args)...);
        }
    }
};

template <typename T1>
struct ranked_overloaded<T1> : T1
{
};

template <typename...Ts>
ranked_overloaded(Ts...) -> ranked_overloaded<Ts...>;

demo

请确保该类型属于特定的名称空间,但是有一个技巧可能会知道是否允许通过ADL找到函数(因此从ns类型继承的类型或> std :: vector&lt; ns :: t0&gt;将通过该检查)

namespace ns
{
    template <typename T>
    void is_found_by_ADL_in_ns(T&&); // Declared only in that namespace
                                     // No definition needed.
}

constexpr auto ns_lambda =
    [](const auto &ns_obj)
    -> decltype(is_found_by_ADL_in_ns(ns_obj), /*return type of the lambda*/)
    {/*..*/};

You might adapt overloaded to have some priorities:

template <typename T1, typename... Ts>
struct ranked_overloaded : T1, ranked_overloaded<Ts...>
{
    template <typename... Us>
    auto operator()(Us&&... args)
    {
        if constexpr (requires{ T1::operator()(std::forward<Us>(args)...); }) {
            return T1::operator()(std::forward<Us>(args)...);
        } else {
            return ranked_overloaded<Ts...>::operator()(std::forward<Us>(args)...);
        }
    }
};

template <typename T1>
struct ranked_overloaded<T1> : T1
{
};

template <typename...Ts>
ranked_overloaded(Ts...) -> ranked_overloaded<Ts...>;

Demo

There is no ways to know for sure that type belongs to a specific namespace, but there is a trick which might be used to know if a type allow to found function via ADL (so types inheriting from ns type, or std::vector<ns::T0> would pass that check)

namespace ns
{
    template <typename T>
    void is_found_by_ADL_in_ns(T&&); // Declared only in that namespace
                                     // No definition needed.
}

constexpr auto ns_lambda =
    [](const auto &ns_obj)
    -> decltype(is_found_by_ADL_in_ns(ns_obj), /*return type of the lambda*/)
    {/*..*/};

Demo

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文