Конструкторы для ваших типов приводят к неоднозначным инициализаторам вариантов.
Если можете, подумайте о том, чтобы сделать их явными.
Кроме того, возвращаемые типы decltype на самом деле не имеют смысла, поскольку посетитель по определению возвращает 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.
Обратите внимание, что последовательное (!) использование аргументов с помощью const& делает выполнение намного более эффективным, особенно для общих указателей.
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");
}
};
Живая демонстрация
Жить на Coliru
#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{...}
person
sehe
schedule
13.12.2020
high_priority
не является SFINAE (но больше похож на отправку тегов). Кроме того, вам это не нужно здесь, см. мой пример. - person sehe   schedule 14.12.2020