Если вы настаиваете, вы можете обернуть своего посетителя посетителем, который предоставит требуемый интерфейс, и объявите , что в качестве друга вашего посетителя-имплантата (который теперь объединяет концепции impl и посетителя).
(«Хороший» (кашель) здесь является то, что не нужно для impl
полиморфными или динамически распределяемой.)
Вот stratight вперед доказательство концепции:
#include <boost/variant.hpp>
namespace detail
{
template <typename R, typename Wrapped>
struct WrapVisitor : boost::static_visitor<R>
{
template <typename... T> R operator()(T&&... args) const { return _wrapped(std::forward<T>(args)...); }
WrapVisitor(Wrapped&& wrapped) : _wrapped(std::move(wrapped)) {}
private:
Wrapped _wrapped;
};
}
template <typename R, typename Wrapped>
detail::WrapVisitor<R, Wrapped> wrap(Wrapped&& wrapped) {
return { std::forward<Wrapped>(wrapped) };
}
А вот как вы будете использовать его с демо-посетителя, который скрывает все детали реализации:
class PrivateVisistorImp : protected boost::static_visitor<double>
{
double operator()(int i) const { return -i; }
double operator()(double d) const { return d*10; }
friend detail::WrapVisitor<double, PrivateVisistorImp>;
};
Конечно, она имеет стоимость необходимости создания экземпляра обернутый посетителя на месте вызова:
int main()
{
using Var = boost::variant<int, double>;
Var a = 3.14, b = 42;
auto w = wrap<double>(PrivateVisistorImp());
std::cout << boost::apply_visitor(w, a) << "\n";
std::cout << boost::apply_visitor(w, b) << "\n";
}
видеть все это Live on Coliru
Почему бы это _need_ быть? Это выглядит как ненужное осложнение для меня. 'apply_visitor' ожидает' static_visitor <> 'производный класс с открытым интерфейсом. Просто поставьте его:/ – sehe
@sehe Мой посетитель - это шаблон шаблона. Поэтому я должен поместить всю логику в заголовок, но я хочу иметь «некоторую остаточную сумму» 'private'ness (чтобы обеспечить инкапсуляцию как можно больше). – Orient
Затем используйте pimpl для «частного» материала. Вы не можете скрыть общий интерфейс. Не нужно. – sehe