Using C++ 17. I have the following:
template <typename T>
using ptr_t = std::shared_ptr<const T>;
class some_type;
class A { some_type foo() const; }
class B { some_type foo() const; }
class C { some_type foo(int) const; }
std::variant<ptr_t<A>, ptr_t<B>, ptr_t<C>>;
A variant holds shared_ptr(s) to different types. All expected to have function foo() that may be void or take a parameter. I will then have a visitor that would correctly dispatch foo, something like this (conceptually):
struct visitor
{
template <typename T>
ptr_t<some_type> operator()(const T& config) const
{
if constexpr (// determine if foo() of the underlying type of a shared_ptr can be called with int param)
return config->foo(15);
else
return config->foo();
}
is there a way to say this? I tried various ways but can't come with something that compiles. Template parameter, T, is ptr_t<A|B|C>.
std::is_invocable_v<Callable, Args...>
is the way to go. Unfortunatelly, it will not compile just like that withif constexpr
. It will either fail because "there is nooperator()()
overload", or there is no overload for operator takingArgs...
.I suggest you add a wrapper class for a callable and use it with a specialized alias template of
std::variant
instead of writing your own visitor. It will allow you to usestd::visit
seamlessly.https://godbolt.org/z/e6GzvW6n6
Take notice, that it does not depend on
if constexpr
. So if you manage to provide your ownvariant
andis_invocable_v
, it will work for C++14. For C++11 possibly, but some modifications regardingconstexpr
functions might be needed.Of course you can implement your
visitor
in the same manner if you want to usestd::shared_ptr
istead of a callable. But I don't see any reason to use:std::shared_ptr
? Do you really need to share the ownership? Just stick withstd::unique_ptr