gpt4 book ai didi

c++ - 实现多类型算术运算符时如何解决 "template argument deduction/substitution failure"

转载 作者:行者123 更新时间:2023-12-02 10:22:56 25 4
gpt4 key购买 nike

我似乎找不到正确的方法来实现它,这似乎是最接近正确的方法,但我得到一个模板参数推导错误。谁能指出我哪里出错了?

我正在尝试将算术功能添加到 std::variant无需std::get第一的:

#include <iostream>
#include <variant>

template<typename... Types>
class variant : public std::variant<Types...> {
private:
template <class Op, typename T, int index = 0>
decltype(auto) calc(const T& other) const {
if(sizeof...(Types) == 0 || index >= sizeof...(Types)){
return;
}

using ST = std::variant_alternative_t<index, std::variant<Types...>>;

if(std::holds_alternative<ST>(
std::variant<Types...>(*this)
)){
if(std::is_same<T, variant<Types...>>::value){
return Op()(std::get<ST>(*this), std::get<ST>(other));
}
else{
return Op()(std::get<ST>(*this), other);
}
}

return this->calc<Op, index+1>(other);
}

public:
using std::variant<Types...>::variant;

template <typename T>
decltype(auto) operator-(const T& other) const {
return this->calc<std::minus>(other);
}

// other operations will be added; std::plus, etc.
};

int main()
{
variant<int, double> vt1 = 2.3;
variant<int, double> vt2 = 5;

std::cout << "first: " << (vt1 - 2) << std::endl;

std::cout << "second: " << (vt2 - vt1) << std::endl;

return 0;
}

最佳答案

你有几个问题:

  • std::minus不是类型,而是模板。它无法绑定(bind)到 class Op .您可能想使用 std::minus<>反而。
  • 当您调用 calc<Op, index + 1>()来自 calc<Op, index>()你得到无限递归。 if开始的条件没有帮助,因为编译器仍然必须生成该调用:在运行时检查此条件,而不是在编译时检查。您需要if constexpr .
  • decltype(auto) 的类型不一致返回类型。所有未丢弃的分支都应返回相同的类型。
  • Op()(std::get<ST>(*this), std::get<ST>(other))如果 *this 会抛出和 other持有不同的类型(在您的示例中,它们确实持有不同的类型)。

  • 而不是修复所有这些并重新发明 std::visit ,您可以简单地定义自由函数并使用 std::visit在实现中:
    namespace impl {
    template<class T>
    auto get_value(const T& t) {
    return t;
    }

    template<class... Ts>
    auto get_value(const std::variant<Ts...>& var) {
    using T = std::common_type_t<Ts...>;
    return std::visit([](T value) { return value; }, var);
    }

    template<class Op, class T, class U>
    auto var_op(Op op, const T& t, const U& u) {
    return op(get_value(t), get_value(u));
    }
    }

    template<class... Ts, class U>
    auto operator-(const std::variant<Ts...>& var, const U& u) {
    return impl::var_op(std::minus<>{}, var, u);
    }

    template<class U, class... Ts>
    auto operator-(const U& u, const std::variant<Ts...>& var) {
    return impl::var_op(std::minus<>{}, u, var);
    }

    template<class... Ts, class... Us>
    auto operator-(const std::variant<Ts...>& var1,
    const std::variant<Us...>& var2) {
    return impl::var_op(std::minus<>{}, var1, var2);
    }

    如果您想将这些功能限制在您自己的类中 my_variant源自 std::variant , 你需要修复 get_value()通过添加 static_cast , 因为 std::visit使用一些不专门用于 std::variant_size 的辅助类(如 my_variant ) :
    template<class... Ts>
    class my_variant : public std::variant<Ts...> {
    public:
    using std::variant<Ts...>::variant;
    };

    ...

    namespace impl {
    template<class... Ts>
    auto get_value(const my_variant<Ts...>& var) {
    using T = std::common_type_t<Ts...>;
    return std::visit([](T value) { return value; },
    static_cast<const std::variant<Ts...>&>(var));
    }
    }

    关于c++ - 实现多类型算术运算符时如何解决 "template argument deduction/substitution failure",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59279624/

    25 4 0