c++14: Templated boost static visitor - c++

I'm implementing a templated boost static visitor that I want to use to return a type.
The visitor will be templated with one type and should throw an error for all other files.
#include <iostream>
#include <stdexcept>
#include <boost/variant/variant.hpp>
#include <boost/variant/static_visitor.hpp>
using namespace std;
template<class Type>
struct GetValue : public boost::static_visitor<Type>
{
template<class Other>
Type operator()(Other&& o) const
{
cout << "called some exception" << endl;
throw std::runtime_error("error");
}
Type operator()(Type& t) const
{
cout << "called correct" << endl;
return std::forward<Type>(t);
}
};
template<class S>
struct Foo : public boost::variant<S, std::string>
{
template <class Type>
Foo(Type&& t)
: boost::variant<Type, std::string>(std::forward<Type>(t))
{}
S operator*() const
{
return boost::apply_visitor(GetValue<S>{}, *this);
}
};
int main()
{
Foo<int> f = 5;
auto foo = *f;
return 0;
}
From what I understand, and sorry if I miss up the terminology, my first operator is a perfect forwarding reference and all calls will be sent there. However, my template type "Type" has already been expanded upon instantiation of the GetValue and thus no calls that I want match the second one that returns the type.
What definition do I need so that when I'm applying the visitor the function I want is called instead of everything referring to the default template.
This is the MVCE: https://godbolt.org/z/T5gd6m
I'm compiling in visual studio 2017 c++14.

Unless you want to provide an overload that can win overload resolution with a forwarding reference (that is, an lvalue reference Type& parameter), you can exclude the unwanted function from consideration through SFINAE:
#include <boost/type_traits.hpp>
template <class Type>
class GetValue : public boost::static_visitor<Type>
{
public:
template <class Other>
auto operator()(Other&& o) const
-> typename boost::disable_if<boost::is_same<typename boost::decay<Other>::type, Type>, Type>::type
{
throw error("Nope.");
}
Type operator()(const Type& t) const
{
return t;
}
};
DEMO

Related

Template type erasure

I am wondering whether there is a practical way of writing something like the following code using the C++17 standard:
#include <string>
#include <functional>
#include <unordered_map>
template <class Arg>
struct Foo
{
using arg_type = Arg;
using fun_type = std::function< void(Arg&) >;
fun_type fun;
void call( Arg& arg ) { fun(arg); }
};
struct Bar
{
using map_type = std::unordered_map<std::string,Foo>; // that's incorrect
map_type map;
auto& operator[] ( std::string name ) { return map[name]; }
};
In the code above, the template argument of class Foo corresponds to the input type of some unary function which returns nothing. Different instances of Foo with different template types correspond to functions taking arguments of different types. The class Bar simply aims at assigning a name to these functions, but obviously the current declaration of the map is incorrect because it needs to know about the template type of Foo.
Or does it?
Doing this with a compile-time check is, unfortunately, not feasible. You can, however, provide that functionality with a runtime check.
A map's value type can only be one single type, and Foo<T> is a different type for each T. However, we can work around this by giving every Foo<T> a common base class, have a map of pointers to it, and use a virtual function to dispatch call() to the appropriate subclass.
For this though, the type of the argument must also always be the same. As mentioned by #MSalters, std::any can help with that.
Finally, we can wrap all that using the pimpl pattern so that it looks like there's just a single neat Foo type:
#include <cassert>
#include <string>
#include <functional>
#include <any>
#include <unordered_map>
#include <memory>
struct Foo {
public:
template<typename T, typename FunT>
void set(FunT fun) {
pimpl_ = std::make_unique<FooImpl<T, FunT>>(std::move(fun));
}
// Using operator()() instead of call() makes this a functor, which
// is a little more flexible.
void operator()(const std::any& arg) {
assert(pimpl_);
pimpl_->call(arg);
}
private:
struct IFooImpl {
virtual ~IFooImpl() = default;
virtual void call( const std::any& arg ) const = 0;
};
template <class Arg, typename FunT>
struct FooImpl : IFooImpl
{
FooImpl(FunT fun) : fun_(std::move(fun)) {}
void call( const std::any& arg ) const override {
fun_(std::any_cast<Arg>(arg));
}
private:
FunT fun_;
};
std::unique_ptr<IFooImpl> pimpl_;
};
// Usage sample
#include <iostream>
void bar(int v) {
std::cout << "bar called with: " << v << "\n";
}
int main() {
std::unordered_map<std::string, Foo> table;
table["aaa"].set<int>(bar);
// Even works with templates/generic lambdas!
table["bbb"].set<float>([](auto x) {
std::cout << "bbb called with " << x << "\n";
});
table["aaa"](14);
table["bbb"](12.0f);
}
see on godbolt

How do you specialize a member function inside a template class?

Let's say I have the following class:
template <typename T>
class SomeClass : Parent<T>
{
public:
// I have a function such as this one:
T DoSomething(const T &t)
{
return t.DoSomething(some_data);
}
// But `T` might be a pointer, so sometimes I will need something like the following
// instead (which obviously doesn't work as given):
T DoSomething(const T &t)
{
return new T(t->DoSomething(some_data));
}
private:
XYZ some_data;
};
I got stuck in a giant mess of template errors trying to implement this in any semi-nice way possible using template specialization.
In the end I came up with this very ugly solution:
template <typename T>
class SomeClass : Parent<T>
{
public:
T DoSomething(const T &x)
{
return Specializer<T>::Do(this, x);
}
private:
template <typename V>
struct Specializer {
static V Do(SomeClass *me, const V &x)
{
return x.DoSomething(me->some_data);
}
};
template <typename V>
struct Specializer<V*> {
static V* Do(SomeClass *me, const V *&x)
{
return new V(x->DoSomething(me->some_data));
}
};
XYZ some_data;
};
Is there a better way to do this that doesn't involve stuffing this function into a dummy class/struct and passing around my this pointer?
PS: In reality, this has nothing to do with pointers, but rather with different types of containers. Pointers were just an easy example to use here.
You can avoid writing any specializations, and use a type trait like std::is_pointer along with if constexpr to decide what code to execute depending on the whether the type is a pointer type or not:
auto DoSomething(const T &t)
{
if constexpr (std::is_pointer_v<T>)
return new T(t->DoSomething(some_data));
else
return t.DoSomething(some_data);
}
If you don't want to check for whether T is a pointer, but want to check something else, you can still use this pattern by dropping in a suitable replacement for is_pointer.
If you have access to c++20, you can clean up the need for any SFINAE, specializations, or if constexpr by using concepts and constraints instead. This just allows you to define the same function N times with different criteria for its insantiation, which is much more readable IMO.
This is almost the same as the SFINAE approach, but without the need for the awful syntax (no std::declval, decltype, etc). It also doesn't require all implementations to exist in one function definition like the if constexpr approach; all you need is separate function definitions with different requires clauses:
#include <concepts>
...
template <typename T>
class SomeClass : Parent<T>
{
public:
// Work for everything that's not specialized
void DoSomething(const T &t)
{
std::cout << "Basic overload" << std::endl;
}
// Only work for pointers
void DoSomething(const T& t) requires(std::is_pointer_v<T>)
{
std::cout << "Pointer overload" << std::endl;
}
// Only work if T is convertible to SomeType
void DoSomething(const T& t) requires(std::convertible_to<T, SomeType>)
{
std::cout << "Convertible to SomeType overload" << std::endl;
}
private:
XYZ some_data;
};
Live Example
In this approach there are 3 different entries:
The basic fallback for all templates
An implementation that works for any pointer type, and
An implementation that works for any T type that may be convertible to SomeType
What about using SFINAE?
For example
#include <utility>
#include <iostream>
template <typename>
struct Parent
{ };
using XYZ = int;
template <typename T>
class SomeClass : Parent<T>
{
public:
template <typename U = T>
auto DoSomething (T const & t)
-> decltype( std::declval<U>().DoSomething(std::declval<XYZ>()) )
{ std::cout << "ref\n"; return t.DoSomething(some_data); }
template <typename U = T>
auto DoSomething (T const & t)
-> std::remove_reference_t<
decltype( std::declval<U>()->DoSomething(std::declval<XYZ>()),
std::declval<T>() )>
{
using V = std::remove_reference_t<decltype(*t)>;
std::cout << "pnt\n"; return new V(t->DoSomething(some_data));
}
private:
XYZ some_data;
};
struct foo
{
foo (foo*) {}
foo () {}
foo DoSomething (int) const { return {}; }
} ;
int main()
{
SomeClass<foo> sc1;
SomeClass<foo*> sc2;
foo f;
sc1.DoSomething(f);
sc2.DoSomething(&f);
}
I mean: what about enabling the first version if, and only if, T is a type that supports a DoSomething(XYZ) method and enabling the second version if, and only if, T is a pointer of a type that supports a DoSomething(XYZ) method?

Template branching with respect to a specific interface type

I'd like to distinguish when a template type implements a given interface. I thought I could achieve this by using a generic template method and its specialization for the interface type interested in. If I the method is call with a type that implements that specific interface, the compiler will resolve it with a call to the specialize method. Otherwise, it will call the generic method. For example, I summarize this idea in in the following code snippet :
#include <iostream>
#include <string>
struct Info {
virtual std::string whoAmI() = 0;
};
struct Person: Info {
std::string whoAmI() { return "Person"; }
};
template<typename T>
bool is_info(const T &)
{
return false;
}
template<>
bool is_info(const Info& )
{
return true;
}
int main()
{
std::cout << is_info(1) << std::endl;
std::cout << is_info(Person()) << std::endl;
}
Unfortunately, this code doesn't work. is_info(Person()) returns 0, when it should return 1. Why? How can I achieve what I need?
Consider using std::is_base_of like this:
#include <type_traits>
template <typename T>
constexpr bool is_info(T const &)
{ return std::is_base_of<Info, typename std::decay<T>::type>::value; }
This also works with boost::is_base_of and boost::decay in pre-C++11:
#include <boost/type_traits.hpp>
template <typename T>
bool is_info(T const &)
{ return boost::is_base_of<Info, typename boost::decay<T>::type>::value; }

How to have std::function or lambda as (optional) template parameter?

Hi I was playing around with TMP and was thinking of generating of a class
that looks something like:
template<typename T, typename LogFunc>
class
{
(where LogFunc should be defaulted to "nop" function)
Idea is to have a class that defines some functionality for instances of type T, for example checks if the number is even, and also has the option to log by calling
void memberFunc(T& t)
{
LogFunc(t);
}
or maybe
void memberFunc(T& t)
{
LogFunc lf;
lf(t);
}
Can it be done?
From reading A on SO, lambdas are kind of problematic as templ params.
BTW if somebody cares this is what I tried but it prints out
:(
The problem is that the type of a lambda is a compiler-enforced singleton; it has only one value, which is the lambda itself; furthermore, the type has a deleted constructor. So you can't pass lambdas as part of a template instantiation, even with decltype. But there's nothing stopping you from passing them as constructor arguments.
However, here we run into another problem: constructor arguments are not used to deduce a template instantiation (which is why the standard library provides utilities like make_pair and make_tuple). So we need a templatized factory function.
With all that, the solution is pretty simple:
template<typename T, typename LogFunc>
class Foo {
public:
Foo(const T& t, LogFunc fn) : t_(t), lfn_(fn) {}
//...
private:
T t_;
LogFunc lfn_;
};
struct Noop {
template<typename...A>
void operator()(A...) { };
};
template<typename T, typename LogFunc=Noop>
Foo<T, LogFunc> make_foo(const T& t, LogFunc func=LogFunc()) {
return Foo<T, LogFunc>(t, func);
}
This will not answer directly, but gives a number of hints about what you did.
The LogFunc parameter is a type (not an object), hence
LogFunc(t) creates a temporary LogFunc giving t as parameter (you are in fact calling the LogFunc::LogFunc(T&) contructor).
LogFunc lf; lf(t); creates a stack-living default contructed Logfunc, named lf, and lf(t) calls its LogFunc::operator()(T&) member function.
LogFunc()(t) creates a temporary default-constructed LogFUnc and calls operator()(T&) on it.
About lambdas, they are in fact classes whose constructor takes the captured varaibles, and whose operator() takes the parameters you declare. But they exist only "internaly" to the compiler, and don't have a "name" you can refer to.
What you can do is deduce its type with a decltype, or with a free-function.
Typically a parametric functional class stores a frunction object, initialized at construction.
#include <iostream>
template<class Fn>
class LogFunc
{
public:
LogFunc(Fn f) :fn(f) {}
template<class T>
void memberFunc(T& t)
{ fn(t); }
private:
Fn fn;
};
template<class Fn>
LogFunc<Fn> makeLogFunc(Fn f)
{ return LogFunc<Fn>(f); }
int main()
{
int x=5;
auto lf = makeLogFunc([](int& a){ std::cout << a << std::endl; });
lf.memberFunc(x);
return 0;
}
compile as "g++ -pedantic -Wall -std=c++11", and will ouptut
5
The other answers are all fine, but you can also just pass in a constructor argument with a std::function<T>. That looks like this:
#include <functional>
#include <iostream>
template <typename T> void someOther(T val){
std::cout << "used other "<<val<<std::endl;
}
template <typename T> void noop(T val){
std::cout << "noop "<<val<<std::endl;
}
template<typename T>
struct A{
A(std::function<void(T)> f =noop<T> ) : mf(f){}
void memberFunc(T valx){
mf(valx);
}
std::function<void(T)> mf;
};
int main(){
A<int> aNoop; ;
A<float> aSomeOther{someOther<float>} ;
aNoop.memberFunc(5);
aSomeOther.memberFunc(3.55);
}
An alternative is to use functor classes, like this:
#include <iostream>
template <typename T> struct OtherC{
void operator()(T v){ std::cout <<"other "<<v<<std::endl; };
};
template <typename T> struct NoopC{
void operator()(T){ std::cout << "noop"<<std::endl; };
};
template<typename T, template <typename X> class F = NoopC >
struct A{
static void memberFunc(T valx){ F<T>()(valx); }
};
int main(){
A<int> aNoop;
A<float,OtherC> aSomeOther ;
aNoop.memberFunc(5);
aSomeOther.memberFunc(3.55);
}

explicit specialization template class member function with different return type

I am trying to port some C++ code from Windows to Solaris(Unix). There are some template code need to be changed. I am using Solaris' compiler CC, g++ should have same issue.
I have a particular part of code introduce some trouble. They are simplified as following:
#include <exception>
#include <cmath>
#include <string>
#include <iostream>
// define the "not implement" error
class tempException: public std::exception
{
public:
virtual const char* what() const throw()
{
return "not been implemented!";
}
} nondeferr;
// the template class
template <typename T>
class A
{
public:
template <typename Val>
Val getValue(T t) { throw nondeferr; }
template<>
double getValue(T t) { return exp( 1.5 * t ); } //Specialize the getValue for double type.
};
// test code
int main()
{
try
{
A<int> testA;
std::cout << testA.getValue<double>(2) << std::endl;
std::cout << testA.getValue<std::string>(2) << std::endl;
}
catch (tempException& e)
{
std::cout << e.what() << std::endl;
}
return 0;
}
To compile this sample code in UNIX, the compilation error comes out as the explicit specialization cannot be in the class A scope.
Here the getValue function only different from the return type, so we cannot modify it using the overload way.
And for some reason, change class A with simple template variable T to class A with double template variables T and Val is not allowed. It will introduce a lots of changes when we try to use this basic class.
May I know if there is any solution? I am currently remove the getValue function, replace it as getDoubleValue... But that is not so good too.
For those who interested, now the class A looks like this:
template <typename T>
class A
{
public:
// the Get Value we want
template <typename R>
R getValue(T t) { return get_value_impl<R>::apply(*this, t); }
// the general get value struct
template<typename R, typename = void>
struct get_value_impl
{
static R apply(A a, T t) { throw nondeferr; }
};
// partial specialization, which is allowed in std C++
template <typename S>
struct get_value_impl<double, S>
{
static double apply(A a, T t) { return exp( 1.5 * t ); }
};
};
The logic behind is explicit specialization is not allowed in standard. However, partial specialization is allowed. Thanks Anycorn again for the splendid solution.
// the template class
template <typename T>
class A {
template<>
double getValue(T t) { return exp( 1.5 * t ); }
};
This isnt allowed by standard.
do:
template <typename T>
class A {
template<class R>
R getValue(T t) { return get_value_impl<double>::apply(*this, t); }
template<class R, class = void>
struct get_value_impl; // specialize this
};
It is not allowed to specialize a member function without specializing the surrounding class. Visual Studio allows this as an extension.