使用 std::visit 对已删除函数进行专门化

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

我正在尝试根据一些先验知识一般地解析一个字符串。 str 被传递给 convert() 并为我想要支持的类型重载,并尝试使用 std::visit() 调用正确的重载:

#include <iostream>
#include <variant>
#include <vector>
#include <charconv>

template <class ...Request, class ...Types>
constexpr bool holdsAlternative(const std::variant<Types...>& v) noexcept
{
   return (std::holds_alternative<Request>(v) || ...);
}
template <typename T>
T convert(const std::string &str) = delete;

template <>
float convert<float>(const std::string &str)
{
    float result = 0;
    std::from_chars(str.data(), str.data() + str.size(), result);
    return result;
}
template <>
int32_t convert<int32_t >(const std::string &str)
{
    int32_t result = 0;
    std::from_chars(str.data(), str.data() + str.size(), result);
    return result;
}
using data_type = std::variant<int32_t, float, std::string>;
std::vector<data_type> Types {float{}, int32_t{}, std::string{}};
int main()
{
    std::string str{"123"};
    bool r = holdsAlternative<int32_t, float>(Types[1]);
    if (r)
    {
       std::visit([&](auto &t) { return convert<decltype(t)>(str); }, Types[1]);
    }
}
c++ variant
1个回答
0
投票

您的代码存在三个问题:

  1. 访问者必须适用于所有可能的变体,所以删除非特化的
    convert
    是行不通的。但是,您可以让非专业版本抛出运行时异常。
  2. 传递给
    std::visit
    的访问者必须对所有变体具有相同的返回类型。如果这对您来说是个问题,则取决于您想要做什么。如果你想通过
    convert
    的输出设置变量值,你没问题:访问者都可以返回
    void
    .
  3. 您应该将
    std::decay_t<decltype(t)>
    作为访问者的模板参数传递,因为
    decltype(t)
    否则会被推断为参考,并且您没有专门化,例如
    float&
    .

这里是固定代码:https://godbolt.org/z/abqv6xKde

#include <iostream>
#include <variant>
#include <vector>
#include <charconv>

template <class ...Request, class ...Types>
constexpr bool holdsAlternative(const std::variant<Types...>& v) noexcept
{
   return (std::holds_alternative<Request>(v) || ...);
}

template <typename T>
T convert(const std::string &str){
    throw std::logic_error("Conversion not supported\n");
};

template <>
float convert<float>(const std::string &str)
{
    std::cout << "float\n";
    float result = 0;
    std::from_chars(str.data(), str.data() + str.size(), result);
    return result;
}
template <>
int32_t convert<int32_t >(const std::string &str)
{
    std::cout << "int32_t\n";
    int32_t result = 0;
    std::from_chars(str.data(), str.data() + str.size(), result);
    return result;
}

using data_type = std::variant<int32_t, float, std::string>;

std::vector<data_type> Types {float{}, int32_t{}, std::string{}};

int main()
{
    std::string str{"123"};
    bool r = holdsAlternative<int32_t, float>(Types[1]);
    if (r)
    {
       std::visit([&](auto &t) { t = convert<std::decay_t<decltype(t)>>(str); }, Types[1]);
    }
}

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