使用访问者时 Boost Variant 转换错误
Boost Variant conversion error when using visitor
我并不是要编写转储代码,但这确实是我可以创建的最小的可重现示例,即使在删除所有逻辑以使其更清晰之后也是如此。
本质上,我试图在 C++ 中实现我自己的一些基本类型版本,通过将类型存储在名为 Values
的 boost::variant 中并使用 boost::static_visitor
s 对 Value
变体执行操作。我试图实现的一个操作是 not equals
运算符,我创建了一个名为 Not_Equal
的访问者来实现此目的。 Not_Equal
运算符将 SFINAE 与 low_priority
和 high_priority
结构结合使用,以确定是否允许运算中使用的两种类型。
Values
变体中的类型是:{SpecialInt
、SpecialBoolean
、std::shared_ptr<SeriesInt>
、std::shared_ptr<SeriesBoolean>
}。
SeriesInt
和SeriesBoolean
之所以是智能指针,是因为在我的真实版本中它们存储了很多信息,所以复制它们会很昂贵。
可接受的!=运算符如下:
SpecialInt != SpecialInt
SpecialBoolean != SpecialBoolean
SeriesInt != SpecialInt
SeriesInt != SeriesInt
SeriesBoolean != SeriesBoolean
由每个 class.
中的运算符重载表示
#include <memory>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant.hpp>
class SpecialBoolean {
public:
SpecialBoolean(bool val) {} //removing this line fixes it
SpecialBoolean() {}
SpecialBoolean operator!= (const SpecialBoolean& rhs) const {
return *this;
}
};
class SpecialInt {
public:
SpecialInt(float val) {} //removing this line fixes it
SpecialInt() {}
SpecialBoolean operator!= (const SpecialInt& rhs) const {
return SpecialBoolean();
}
};
class SeriesBoolean {
public:
SeriesBoolean() {}
std::shared_ptr<SeriesBoolean> operator!= (const SpecialBoolean& rhs) const {
return std::make_shared<SeriesBoolean>();
}
std::shared_ptr<SeriesBoolean> operator!= (const SeriesBoolean& rhs) const {
return std::make_shared<SeriesBoolean>();
}
};
class SeriesInt {
public:
SeriesInt() {}
std::shared_ptr<SeriesBoolean> operator!= (const SpecialInt& rhs) const {
return std::make_shared<SeriesBoolean>();
}
std::shared_ptr<SeriesBoolean> operator!= (const SeriesInt& rhs) const {
return std::make_shared<SeriesBoolean>();
}
};
typedef boost::variant <SpecialInt, SpecialBoolean, std::shared_ptr<SeriesInt>, std::shared_ptr<SeriesBoolean> > Values;
struct low_priority {};
struct high_priority : low_priority {};
struct Not_Equal : public boost::static_visitor<Values> {
auto operator() (Values const& a, Values const& b) const {
return boost::apply_visitor(*this, a, b);
}
template <typename T, typename U>
auto operator() (high_priority, T a, U b) const -> decltype(Values(a != b)) {
return a != b; // problem here
}
template <typename T, typename U>
auto operator() (high_priority, std::shared_ptr<T> a, std::shared_ptr<U> b) const -> decltype(Values(*a != *b)) {
return *a != *b;
}
template <typename T, typename U>
auto operator() (high_priority, std::shared_ptr<T> a, U b) const -> decltype(Values(*a != b)) {
return *a != b;
}
template <typename T, typename U>
Values operator() (low_priority, T, U) const {
throw std::runtime_error("Incompatible arguments");
}
template <typename T, typename U>
Values operator() (T a, U b) const {
return (*this)(high_priority{}, a, b);
}
};
问题出现在第 return a != b;
行的访问者中,其中运算符类型不是 shared_ptr,因此 SpecialInt
或 SpecialBoolean
导致错误:
Error C2446 '!=': no conversion from 'SeriesInt *' to 'SeriesBoolean *'
Error C2446 '!=': no conversion from 'SeriesBoolean *' to 'SeriesInt *'
我不明白它与 SeriesBoolean*
或 SeriesInt*
有什么关系,因为它只能接受 SpecialInt
和 SpecialBoolean
的类型,但我已经注意到当我删除在 SpecialInt
和 SpecialBoolean
中接受参数的构造函数时,代码会正常编译和运行。我需要那些构造函数将值加载到 classes(逻辑已删除)所以我的问题是为什么我会收到这些错误以及如何解决这个问题?
您的类型的构造函数导致变体初始值设定项不明确。
如果可以,请考虑将它们明确化。
此外,decltype return 类型实际上没有意义,因为根据定义,访问者 returns Values
。
这个超载
template <typename T, typename U>
Values operator()(high_priority, T a, U b) const {
return a != b; // problem here
}
匹配所有组合。 operator !=
在这种情况下/未定义/。您是想这样做吗:
template <typename T>
Values operator()(high_priority, T const& a, T const& b) const {
return a != b; // problem here
}
现在您还需要以下重载:
template <typename T>
Values operator()(high_priority, std::shared_ptr<T> const& a, std::shared_ptr<T> const& b) const {
return *a != *b;
}
否则两个相同的 shared_pointer 参数类型会产生歧义。
这个重载似乎是错误的:
template <typename T, typename U>
Values operator()(high_priority, std::shared_ptr<T> const& a, std::shared_ptr<U> const& b) const {
return *a != *b;
}
这显然会导致问题,因为它会例如将 SeriesInt
与未实现的 SeriesBool
进行比较。由于它不在您的列表中,因此请删除它。
同样,因为
template <typename T, typename U>
Values operator()(high_priority, std::shared_ptr<T> const& a, U const& b) const {
return *a != b;
}
也匹配 [T = SeriesInt, U = SpecialBoolean ],它不会编译。
简化!
我基本上会 运行 列出受支持的重载列表,然后 明确地 实现它们。我将仅在 1:1.
的情况下使用上述模板
Note that consistently (!) taking args by const& make the execution a lot more efficient especially for the shared pointers.
struct Not_Equal : boost::static_visitor<Values> {
Values operator()(Values const& a, Values const& b) const {
return boost::apply_visitor(*this, a, b);
}
// SpecialInt != SpecialInt
// SpecialBoolean != SpecialBoolean
template <typename T>
Values operator()(T const& a, T const& b) const {
return a != b;
}
// SeriesInt != SeriesInt
// SeriesBoolean != SeriesBoolean
template <typename T>
Values operator()(std::shared_ptr<T> const& a, std::shared_ptr<T> const& b) const {
return *a != *b;
}
// SeriesInt != SpecialInt
Values operator()(std::shared_ptr<SeriesInt> const& a, SpecialInt const& b) const {
return *a != b;
}
template <typename... T>
Values operator()(T const&...) const {
throw std::runtime_error("Incompatible arguments");
}
};
现场演示
#include <boost/variant.hpp>
#include <boost/variant/static_visitor.hpp>
#include <memory>
struct SpecialBoolean {
explicit SpecialBoolean(bool /*val*/ = false) {}
SpecialBoolean operator!=(const SpecialBoolean& /*rhs*/) const { return *this; }
};
struct SpecialInt {
explicit SpecialInt(float /*val*/ = 0) {}
SpecialBoolean operator!=(const SpecialInt& /*rhs*/) const {
return SpecialBoolean();
}
};
struct SeriesBoolean {
SeriesBoolean() {}
std::shared_ptr<SeriesBoolean> operator!=(const SpecialBoolean& /*rhs*/) const {
return std::make_shared<SeriesBoolean>();
}
std::shared_ptr<SeriesBoolean> operator!=(const SeriesBoolean& /*rhs*/) const {
return std::make_shared<SeriesBoolean>();
}
};
struct SeriesInt {
SeriesInt() {}
std::shared_ptr<SeriesBoolean> operator!=(const SpecialInt& /*rhs*/) const {
return std::make_shared<SeriesBoolean>();
}
std::shared_ptr<SeriesBoolean> operator!=(const SeriesInt& /*rhs*/) const {
return std::make_shared<SeriesBoolean>();
}
};
typedef boost::variant<
SpecialInt,
SpecialBoolean,
std::shared_ptr<SeriesInt>,
std::shared_ptr<SeriesBoolean>
>
Values;
struct Not_Equal : boost::static_visitor<Values> {
Values operator()(Values const& a, Values const& b) const {
return boost::apply_visitor(*this, a, b);
}
// SpecialInt != SpecialInt
// SpecialBoolean != SpecialBoolean
template <typename T>
Values operator()(T const& a, T const& b) const {
return a != b;
}
// SeriesInt != SeriesInt
// SeriesBoolean != SeriesBoolean
template <typename T>
Values operator()(std::shared_ptr<T> const& a, std::shared_ptr<T> const& b) const {
return *a != *b;
}
// SeriesInt != SpecialInt
Values operator()(std::shared_ptr<SeriesInt> const& a, SpecialInt const& b) const {
return *a != b;
}
template <typename... T>
Values operator()(T const&...) const {
throw std::runtime_error("Incompatible arguments");
}
};
int main() {
}
奖金
此外,我认为你应该封装使用 shared_ptr<> 的 优化,消除所有特殊情况。
这将以上所有内容简化为:
struct Not_Equal : boost::static_visitor<Values> {
Values operator()(Values const& a, Values const& b) const {
return boost::apply_visitor(*this, a, b);
}
template <typename T>
Values operator()(T const& a, T const& b) const { return a != b; }
Values operator()(SeriesInt const& a, SpecialInt const& b) const { return a != b; }
Values operator()(SeriesBoolean const& a, SpecialBoolean const& b) const { return a != b; }
template <typename... T>
Values operator()(T const&...) const {
throw std::runtime_error("Incompatible arguments");
}
};
这是一个带有测试用例的完整演示 Live On Coliru
#include <boost/variant.hpp>
#include <boost/variant/static_visitor.hpp>
#include <memory>
#include <vector>
#include <iostream>
#include <iomanip>
struct SpecialBoolean {
explicit SpecialBoolean(bool val = false) : val(val) {}
SpecialBoolean operator!=(const SpecialBoolean& rhs) const { return SpecialBoolean{val != rhs.val}; }
private:
bool val;
friend std::ostream& operator<<(std::ostream& os, SpecialBoolean const& b) { return os << "SpecialBoolean{" << std::boolalpha << b.val << "}"; }
};
struct SpecialInt {
explicit SpecialInt(float val = false) : val(val) {}
SpecialBoolean operator!=(const SpecialInt& rhs) const { return SpecialBoolean{val != rhs.val}; }
private:
float val;
friend std::ostream& operator<<(std::ostream& os, SpecialInt const& i) { return os << "SpecialInt{" << i.val << "}"; }
};
struct SeriesBoolean {
SeriesBoolean operator!=(const SpecialBoolean& /*rhs*/) const { return {}; } // TODO
SeriesBoolean operator!=(const SeriesBoolean& /*rhs*/) const { return {}; } // TODO
private:
struct VeryLarge {
std::array<SpecialBoolean, 512> _it_is;
};
std::shared_ptr<VeryLarge> _data = std::make_shared<VeryLarge>();
friend std::ostream& operator<<(std::ostream& os, SeriesBoolean const&) { return os << "SeriesBoolean{...}"; }
};
struct SeriesInt {
SeriesBoolean operator!=(const SpecialInt& /*rhs*/) const { return {}; }
SeriesBoolean operator!=(const SeriesInt& /*rhs*/) const { return {}; }
private:
struct VeryLarge {
std::array<SpecialInt, 512> _it_is;
};
std::shared_ptr<VeryLarge> _data = std::make_shared<VeryLarge>();
friend std::ostream& operator<<(std::ostream& os, SeriesInt const&) { return os << "SeriesInt{...}"; }
};
using Values = boost::variant< SpecialInt, SpecialBoolean, SeriesInt, SeriesBoolean >;
struct Not_Equal : boost::static_visitor<Values> {
Values operator()(Values const& a, Values const& b) const {
return boost::apply_visitor(*this, a, b);
}
template <typename T>
Values operator()(T const& a, T const& b) const { return a != b; }
Values operator()(SeriesInt const& a, SpecialInt const& b) const { return a != b; }
Values operator()(SeriesBoolean const& a, SpecialBoolean const& b) const { return a != b; }
template <typename... T>
Values operator()(T const&...) const {
throw std::runtime_error("Incompatible arguments");
}
};
int main() {
Values const vv[] = {
SpecialInt(42),
SpecialInt(-314e-2),
SpecialBoolean(false),
SpecialBoolean(true),
SeriesInt(),
SeriesBoolean()
};
Not_Equal const neq;
auto col = [](auto const& v, bool right = false) -> auto& {
std::ostringstream ss; // just for quick formatting
ss << v;
if (right)
std::cout << std::right;
else
std::cout << std::left;
return std::cout << std::setw(21) << ss.str();
};
for (auto const& a: vv) for (auto const& b: vv) try {
col(a, true) << " != ";
col(b) << " --> ";
col(neq(a, b)) << "\n";
} catch(std::exception const& e) {
col(e.what()) << "\n";
}
}
打印
SpecialInt{42} != SpecialInt{42} --> SpecialBoolean{false}
SpecialInt{42} != SpecialInt{-3.14} --> SpecialBoolean{true}
SpecialInt{42} != SpecialBoolean{false} --> Incompatible arguments
SpecialInt{42} != SpecialBoolean{true} --> Incompatible arguments
SpecialInt{42} != SeriesInt{...} --> Incompatible arguments
SpecialInt{42} != SeriesBoolean{...} --> Incompatible arguments
SpecialInt{-3.14} != SpecialInt{42} --> SpecialBoolean{true}
SpecialInt{-3.14} != SpecialInt{-3.14} --> SpecialBoolean{false}
SpecialInt{-3.14} != SpecialBoolean{false} --> Incompatible arguments
SpecialInt{-3.14} != SpecialBoolean{true} --> Incompatible arguments
SpecialInt{-3.14} != SeriesInt{...} --> Incompatible arguments
SpecialInt{-3.14} != SeriesBoolean{...} --> Incompatible arguments
SpecialBoolean{false} != SpecialInt{42} --> Incompatible arguments
SpecialBoolean{false} != SpecialInt{-3.14} --> Incompatible arguments
SpecialBoolean{false} != SpecialBoolean{false} --> SpecialBoolean{false}
SpecialBoolean{false} != SpecialBoolean{true} --> SpecialBoolean{true}
SpecialBoolean{false} != SeriesInt{...} --> Incompatible arguments
SpecialBoolean{false} != SeriesBoolean{...} --> Incompatible arguments
SpecialBoolean{true} != SpecialInt{42} --> Incompatible arguments
SpecialBoolean{true} != SpecialInt{-3.14} --> Incompatible arguments
SpecialBoolean{true} != SpecialBoolean{false} --> SpecialBoolean{true}
SpecialBoolean{true} != SpecialBoolean{true} --> SpecialBoolean{false}
SpecialBoolean{true} != SeriesInt{...} --> Incompatible arguments
SpecialBoolean{true} != SeriesBoolean{...} --> Incompatible arguments
SeriesInt{...} != SpecialInt{42} --> SeriesBoolean{...}
SeriesInt{...} != SpecialInt{-3.14} --> SeriesBoolean{...}
SeriesInt{...} != SpecialBoolean{false} --> Incompatible arguments
SeriesInt{...} != SpecialBoolean{true} --> Incompatible arguments
SeriesInt{...} != SeriesInt{...} --> SeriesBoolean{...}
SeriesInt{...} != SeriesBoolean{...} --> Incompatible arguments
SeriesBoolean{...} != SpecialInt{42} --> Incompatible arguments
SeriesBoolean{...} != SpecialInt{-3.14} --> Incompatible arguments
SeriesBoolean{...} != SpecialBoolean{false} --> SeriesBoolean{...}
SeriesBoolean{...} != SpecialBoolean{true} --> SeriesBoolean{...}
SeriesBoolean{...} != SeriesInt{...} --> Incompatible arguments
SeriesBoolean{...} != SeriesBoolean{...} --> SeriesBoolean{...}
我并不是要编写转储代码,但这确实是我可以创建的最小的可重现示例,即使在删除所有逻辑以使其更清晰之后也是如此。
本质上,我试图在 C++ 中实现我自己的一些基本类型版本,通过将类型存储在名为 Values
的 boost::variant 中并使用 boost::static_visitor
s 对 Value
变体执行操作。我试图实现的一个操作是 not equals
运算符,我创建了一个名为 Not_Equal
的访问者来实现此目的。 Not_Equal
运算符将 SFINAE 与 low_priority
和 high_priority
结构结合使用,以确定是否允许运算中使用的两种类型。
Values
变体中的类型是:{SpecialInt
、SpecialBoolean
、std::shared_ptr<SeriesInt>
、std::shared_ptr<SeriesBoolean>
}。
SeriesInt
和SeriesBoolean
之所以是智能指针,是因为在我的真实版本中它们存储了很多信息,所以复制它们会很昂贵。
可接受的!=运算符如下:
SpecialInt != SpecialInt
SpecialBoolean != SpecialBoolean
SeriesInt != SpecialInt
SeriesInt != SeriesInt
SeriesBoolean != SeriesBoolean
由每个 class.
中的运算符重载表示#include <memory>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant.hpp>
class SpecialBoolean {
public:
SpecialBoolean(bool val) {} //removing this line fixes it
SpecialBoolean() {}
SpecialBoolean operator!= (const SpecialBoolean& rhs) const {
return *this;
}
};
class SpecialInt {
public:
SpecialInt(float val) {} //removing this line fixes it
SpecialInt() {}
SpecialBoolean operator!= (const SpecialInt& rhs) const {
return SpecialBoolean();
}
};
class SeriesBoolean {
public:
SeriesBoolean() {}
std::shared_ptr<SeriesBoolean> operator!= (const SpecialBoolean& rhs) const {
return std::make_shared<SeriesBoolean>();
}
std::shared_ptr<SeriesBoolean> operator!= (const SeriesBoolean& rhs) const {
return std::make_shared<SeriesBoolean>();
}
};
class SeriesInt {
public:
SeriesInt() {}
std::shared_ptr<SeriesBoolean> operator!= (const SpecialInt& rhs) const {
return std::make_shared<SeriesBoolean>();
}
std::shared_ptr<SeriesBoolean> operator!= (const SeriesInt& rhs) const {
return std::make_shared<SeriesBoolean>();
}
};
typedef boost::variant <SpecialInt, SpecialBoolean, std::shared_ptr<SeriesInt>, std::shared_ptr<SeriesBoolean> > Values;
struct low_priority {};
struct high_priority : low_priority {};
struct Not_Equal : public boost::static_visitor<Values> {
auto operator() (Values const& a, Values const& b) const {
return boost::apply_visitor(*this, a, b);
}
template <typename T, typename U>
auto operator() (high_priority, T a, U b) const -> decltype(Values(a != b)) {
return a != b; // problem here
}
template <typename T, typename U>
auto operator() (high_priority, std::shared_ptr<T> a, std::shared_ptr<U> b) const -> decltype(Values(*a != *b)) {
return *a != *b;
}
template <typename T, typename U>
auto operator() (high_priority, std::shared_ptr<T> a, U b) const -> decltype(Values(*a != b)) {
return *a != b;
}
template <typename T, typename U>
Values operator() (low_priority, T, U) const {
throw std::runtime_error("Incompatible arguments");
}
template <typename T, typename U>
Values operator() (T a, U b) const {
return (*this)(high_priority{}, a, b);
}
};
问题出现在第 return a != b;
行的访问者中,其中运算符类型不是 shared_ptr,因此 SpecialInt
或 SpecialBoolean
导致错误:
Error C2446 '!=': no conversion from 'SeriesInt *' to 'SeriesBoolean *'
Error C2446 '!=': no conversion from 'SeriesBoolean *' to 'SeriesInt *'
我不明白它与 SeriesBoolean*
或 SeriesInt*
有什么关系,因为它只能接受 SpecialInt
和 SpecialBoolean
的类型,但我已经注意到当我删除在 SpecialInt
和 SpecialBoolean
中接受参数的构造函数时,代码会正常编译和运行。我需要那些构造函数将值加载到 classes(逻辑已删除)所以我的问题是为什么我会收到这些错误以及如何解决这个问题?
您的类型的构造函数导致变体初始值设定项不明确。
如果可以,请考虑将它们明确化。
此外,decltype return 类型实际上没有意义,因为根据定义,访问者 returns Values
。
这个超载
template <typename T, typename U>
Values operator()(high_priority, T a, U b) const {
return a != b; // problem here
}
匹配所有组合。 operator !=
在这种情况下/未定义/。您是想这样做吗:
template <typename T>
Values operator()(high_priority, T const& a, T const& b) const {
return a != b; // problem here
}
现在您还需要以下重载:
template <typename T>
Values operator()(high_priority, std::shared_ptr<T> const& a, std::shared_ptr<T> const& b) const {
return *a != *b;
}
否则两个相同的 shared_pointer 参数类型会产生歧义。
这个重载似乎是错误的:
template <typename T, typename U>
Values operator()(high_priority, std::shared_ptr<T> const& a, std::shared_ptr<U> const& b) const {
return *a != *b;
}
这显然会导致问题,因为它会例如将 SeriesInt
与未实现的 SeriesBool
进行比较。由于它不在您的列表中,因此请删除它。
同样,因为
template <typename T, typename U>
Values operator()(high_priority, std::shared_ptr<T> const& a, U const& b) const {
return *a != b;
}
也匹配 [T = SeriesInt, U = SpecialBoolean ],它不会编译。
简化!
我基本上会 运行 列出受支持的重载列表,然后 明确地 实现它们。我将仅在 1:1.
的情况下使用上述模板Note that consistently (!) taking args by const& make the execution a lot more efficient especially for the shared pointers.
struct Not_Equal : boost::static_visitor<Values> {
Values operator()(Values const& a, Values const& b) const {
return boost::apply_visitor(*this, a, b);
}
// SpecialInt != SpecialInt
// SpecialBoolean != SpecialBoolean
template <typename T>
Values operator()(T const& a, T const& b) const {
return a != b;
}
// SeriesInt != SeriesInt
// SeriesBoolean != SeriesBoolean
template <typename T>
Values operator()(std::shared_ptr<T> const& a, std::shared_ptr<T> const& b) const {
return *a != *b;
}
// SeriesInt != SpecialInt
Values operator()(std::shared_ptr<SeriesInt> const& a, SpecialInt const& b) const {
return *a != b;
}
template <typename... T>
Values operator()(T const&...) const {
throw std::runtime_error("Incompatible arguments");
}
};
现场演示
#include <boost/variant.hpp>
#include <boost/variant/static_visitor.hpp>
#include <memory>
struct SpecialBoolean {
explicit SpecialBoolean(bool /*val*/ = false) {}
SpecialBoolean operator!=(const SpecialBoolean& /*rhs*/) const { return *this; }
};
struct SpecialInt {
explicit SpecialInt(float /*val*/ = 0) {}
SpecialBoolean operator!=(const SpecialInt& /*rhs*/) const {
return SpecialBoolean();
}
};
struct SeriesBoolean {
SeriesBoolean() {}
std::shared_ptr<SeriesBoolean> operator!=(const SpecialBoolean& /*rhs*/) const {
return std::make_shared<SeriesBoolean>();
}
std::shared_ptr<SeriesBoolean> operator!=(const SeriesBoolean& /*rhs*/) const {
return std::make_shared<SeriesBoolean>();
}
};
struct SeriesInt {
SeriesInt() {}
std::shared_ptr<SeriesBoolean> operator!=(const SpecialInt& /*rhs*/) const {
return std::make_shared<SeriesBoolean>();
}
std::shared_ptr<SeriesBoolean> operator!=(const SeriesInt& /*rhs*/) const {
return std::make_shared<SeriesBoolean>();
}
};
typedef boost::variant<
SpecialInt,
SpecialBoolean,
std::shared_ptr<SeriesInt>,
std::shared_ptr<SeriesBoolean>
>
Values;
struct Not_Equal : boost::static_visitor<Values> {
Values operator()(Values const& a, Values const& b) const {
return boost::apply_visitor(*this, a, b);
}
// SpecialInt != SpecialInt
// SpecialBoolean != SpecialBoolean
template <typename T>
Values operator()(T const& a, T const& b) const {
return a != b;
}
// SeriesInt != SeriesInt
// SeriesBoolean != SeriesBoolean
template <typename T>
Values operator()(std::shared_ptr<T> const& a, std::shared_ptr<T> const& b) const {
return *a != *b;
}
// SeriesInt != SpecialInt
Values operator()(std::shared_ptr<SeriesInt> const& a, SpecialInt const& b) const {
return *a != b;
}
template <typename... T>
Values operator()(T const&...) const {
throw std::runtime_error("Incompatible arguments");
}
};
int main() {
}
奖金
此外,我认为你应该封装使用 shared_ptr<> 的 优化,消除所有特殊情况。
这将以上所有内容简化为:
struct Not_Equal : boost::static_visitor<Values> {
Values operator()(Values const& a, Values const& b) const {
return boost::apply_visitor(*this, a, b);
}
template <typename T>
Values operator()(T const& a, T const& b) const { return a != b; }
Values operator()(SeriesInt const& a, SpecialInt const& b) const { return a != b; }
Values operator()(SeriesBoolean const& a, SpecialBoolean const& b) const { return a != b; }
template <typename... T>
Values operator()(T const&...) const {
throw std::runtime_error("Incompatible arguments");
}
};
这是一个带有测试用例的完整演示 Live On Coliru
#include <boost/variant.hpp>
#include <boost/variant/static_visitor.hpp>
#include <memory>
#include <vector>
#include <iostream>
#include <iomanip>
struct SpecialBoolean {
explicit SpecialBoolean(bool val = false) : val(val) {}
SpecialBoolean operator!=(const SpecialBoolean& rhs) const { return SpecialBoolean{val != rhs.val}; }
private:
bool val;
friend std::ostream& operator<<(std::ostream& os, SpecialBoolean const& b) { return os << "SpecialBoolean{" << std::boolalpha << b.val << "}"; }
};
struct SpecialInt {
explicit SpecialInt(float val = false) : val(val) {}
SpecialBoolean operator!=(const SpecialInt& rhs) const { return SpecialBoolean{val != rhs.val}; }
private:
float val;
friend std::ostream& operator<<(std::ostream& os, SpecialInt const& i) { return os << "SpecialInt{" << i.val << "}"; }
};
struct SeriesBoolean {
SeriesBoolean operator!=(const SpecialBoolean& /*rhs*/) const { return {}; } // TODO
SeriesBoolean operator!=(const SeriesBoolean& /*rhs*/) const { return {}; } // TODO
private:
struct VeryLarge {
std::array<SpecialBoolean, 512> _it_is;
};
std::shared_ptr<VeryLarge> _data = std::make_shared<VeryLarge>();
friend std::ostream& operator<<(std::ostream& os, SeriesBoolean const&) { return os << "SeriesBoolean{...}"; }
};
struct SeriesInt {
SeriesBoolean operator!=(const SpecialInt& /*rhs*/) const { return {}; }
SeriesBoolean operator!=(const SeriesInt& /*rhs*/) const { return {}; }
private:
struct VeryLarge {
std::array<SpecialInt, 512> _it_is;
};
std::shared_ptr<VeryLarge> _data = std::make_shared<VeryLarge>();
friend std::ostream& operator<<(std::ostream& os, SeriesInt const&) { return os << "SeriesInt{...}"; }
};
using Values = boost::variant< SpecialInt, SpecialBoolean, SeriesInt, SeriesBoolean >;
struct Not_Equal : boost::static_visitor<Values> {
Values operator()(Values const& a, Values const& b) const {
return boost::apply_visitor(*this, a, b);
}
template <typename T>
Values operator()(T const& a, T const& b) const { return a != b; }
Values operator()(SeriesInt const& a, SpecialInt const& b) const { return a != b; }
Values operator()(SeriesBoolean const& a, SpecialBoolean const& b) const { return a != b; }
template <typename... T>
Values operator()(T const&...) const {
throw std::runtime_error("Incompatible arguments");
}
};
int main() {
Values const vv[] = {
SpecialInt(42),
SpecialInt(-314e-2),
SpecialBoolean(false),
SpecialBoolean(true),
SeriesInt(),
SeriesBoolean()
};
Not_Equal const neq;
auto col = [](auto const& v, bool right = false) -> auto& {
std::ostringstream ss; // just for quick formatting
ss << v;
if (right)
std::cout << std::right;
else
std::cout << std::left;
return std::cout << std::setw(21) << ss.str();
};
for (auto const& a: vv) for (auto const& b: vv) try {
col(a, true) << " != ";
col(b) << " --> ";
col(neq(a, b)) << "\n";
} catch(std::exception const& e) {
col(e.what()) << "\n";
}
}
打印
SpecialInt{42} != SpecialInt{42} --> SpecialBoolean{false}
SpecialInt{42} != SpecialInt{-3.14} --> SpecialBoolean{true}
SpecialInt{42} != SpecialBoolean{false} --> Incompatible arguments
SpecialInt{42} != SpecialBoolean{true} --> Incompatible arguments
SpecialInt{42} != SeriesInt{...} --> Incompatible arguments
SpecialInt{42} != SeriesBoolean{...} --> Incompatible arguments
SpecialInt{-3.14} != SpecialInt{42} --> SpecialBoolean{true}
SpecialInt{-3.14} != SpecialInt{-3.14} --> SpecialBoolean{false}
SpecialInt{-3.14} != SpecialBoolean{false} --> Incompatible arguments
SpecialInt{-3.14} != SpecialBoolean{true} --> Incompatible arguments
SpecialInt{-3.14} != SeriesInt{...} --> Incompatible arguments
SpecialInt{-3.14} != SeriesBoolean{...} --> Incompatible arguments
SpecialBoolean{false} != SpecialInt{42} --> Incompatible arguments
SpecialBoolean{false} != SpecialInt{-3.14} --> Incompatible arguments
SpecialBoolean{false} != SpecialBoolean{false} --> SpecialBoolean{false}
SpecialBoolean{false} != SpecialBoolean{true} --> SpecialBoolean{true}
SpecialBoolean{false} != SeriesInt{...} --> Incompatible arguments
SpecialBoolean{false} != SeriesBoolean{...} --> Incompatible arguments
SpecialBoolean{true} != SpecialInt{42} --> Incompatible arguments
SpecialBoolean{true} != SpecialInt{-3.14} --> Incompatible arguments
SpecialBoolean{true} != SpecialBoolean{false} --> SpecialBoolean{true}
SpecialBoolean{true} != SpecialBoolean{true} --> SpecialBoolean{false}
SpecialBoolean{true} != SeriesInt{...} --> Incompatible arguments
SpecialBoolean{true} != SeriesBoolean{...} --> Incompatible arguments
SeriesInt{...} != SpecialInt{42} --> SeriesBoolean{...}
SeriesInt{...} != SpecialInt{-3.14} --> SeriesBoolean{...}
SeriesInt{...} != SpecialBoolean{false} --> Incompatible arguments
SeriesInt{...} != SpecialBoolean{true} --> Incompatible arguments
SeriesInt{...} != SeriesInt{...} --> SeriesBoolean{...}
SeriesInt{...} != SeriesBoolean{...} --> Incompatible arguments
SeriesBoolean{...} != SpecialInt{42} --> Incompatible arguments
SeriesBoolean{...} != SpecialInt{-3.14} --> Incompatible arguments
SeriesBoolean{...} != SpecialBoolean{false} --> SeriesBoolean{...}
SeriesBoolean{...} != SpecialBoolean{true} --> SeriesBoolean{...}
SeriesBoolean{...} != SeriesInt{...} --> Incompatible arguments
SeriesBoolean{...} != SeriesBoolean{...} --> SeriesBoolean{...}