C++ enable_if_t SFINAE - c++

I am trying to understand why this piece is code isn't working as expected
#include <cstdio>
#include <vector>
#include <type_traits>
using namespace std;
struct Foo {
};
template<typename T, typename = void>
void compare(const T&a, const T&b) {
cout << "default" << endl;
}
template<typename T, std::enable_if_t<std::is_same<T, Foo>::value>>
void compare(const T& a, const T &b) {
cout << "In object" << endl;
}
int main(int argc, char const *argv[]) {
compare(1, 2);
{
vector<int> a, b;
compare(a, b);
}
{
Foo a, b;
compare(a, b);
}
return 0;
}
In all cases "default" is printed. For the last case I would expect that the 2nd function to get invoked.

You didn't specialize compare (it's impossible to partially specialize a function template anyway). Instead you provide an overload.
And the overload is always illegal:
Either enable_if_t is not defined.
Or it specifies a non-type template parameter of type void.
So it's never going to be called, because SFINAE discards it in favor of the always valid overload at the top.
Specialization is usually the wrong answer for function templates. Instead you should delegate to a class template, which will behave as expected upon true specialization:
template<typename T, typename = void>
struct compare_impl {
static void execute(T const& l, T const& r) { /*Base case code*/ }
};
template<typename T>
struct compare_impl<T, std::enable_if_t<std::is_same<T, Foo>::value>> {
static void execute(T const& l, T const& r) { /*Special case code*/ }
};
template<typename T>
void compare (T const& l, T const& r) { compare_impl<T>::execute(a, b); }

Using a class template is a valid solution, here's another way to achieve this result with tag dispatching:
template <class T>
void compare(const T & l, const T & r, std::true_type)
{
cout << "In object" << endl;
}
template <class T>
void compare(const T & l, const T & r, std::false_type)
{
cout << "default" << endl;
}
template <class T>
void compare(const T & l, const T & r)
{
compare(l, r, std::is_same<T, Foo>{});
}

Deferring to a specialised function object allows a lot of flexibility on how argument types and/or whether they are rvalues or lvalues.
#include <iostream>
#include <vector>
#include <type_traits>
using namespace std;
// general case
template<class T>
struct compare_impl
{
template<class U, class V>
auto operator()(U&& a, V&& b) const {
cout << "default" << endl;
}
};
// compare interface
template<class T, class U>
auto compare(T && a, U && b)
{
using ctype = std::common_type_t<std::decay_t<T>, std::decay_t<U>>;
auto impl = compare_impl<ctype>();
return impl(a, b);
}
// now specialise for objects for which we want custom behaviour
struct Foo {
};
template<>
struct compare_impl<Foo>
{
template<class U, class V>
auto operator()(U&& a, V&& b) const {
cout << "In object" << endl;
}
};
int main(int argc, char const *argv[]) {
compare(1, 2);
{
vector<int> a, b;
compare(a, b);
}
{
Foo a, b;
compare(a, b);
}
return 0;
}

Related

Compiler differences with use of templated overloads

I have a pretty specific situation where I'm feeding a bunch of data to a hasher-like class. In particular, one data type that I use has a member whose type depends on the supertype's type parameter. Long story short, here's a piece of code that illustrates this behaviour :
#include <assert.h>
#include <iostream>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
// Some dummy priority structs to select overloads
struct priority0 { };
struct priority1 : priority0 { };
// This is the hasher-like function
struct Catcher
{
// Ideally we feed everything to this object through here
template <typename T> Catcher& operator<<(const T& v)
{
add(v, priority1{}); // always attempt to call the highest-priority overload
return *this;
}
// For floating-point data types
template <typename T> auto add(const T& v, priority1) -> std::enable_if_t<std::is_floating_point_v<T>, void>
{
std::cout << "caught float/double : " << v << std::endl;
}
// For ranges
template <class T> auto add(const T& range, priority1) -> decltype(begin(range), end(range), void())
{
for(auto const& v : range)
*this << v;
}
// For chars
void add(char c, priority1)
{
std::cout << c;
std::cout.flush();
}
// When everything else fails ; ideally should never happen
template <typename T> void add(const T& v, priority0)
{
assert(false && "should never happen");
}
};
// The one data type. Notice how the primary template and the
// specialization have a `range` member of different types
template <class T> struct ValueOrRange
{
struct Range
{
T min;
T max;
};
Range range;
T value;
};
template <> struct ValueOrRange<std::string>
{
std::vector<std::string> range;
std::string value;
};
// Overload operator<< for Catcher outside of the
// class to allow for processing of the new data type
// Also overload that for `ValueOrRange<T>::Range`. SFINAE should make sure
// that this behaves correctly (?)
template <class T> Catcher& operator<<(Catcher& c, const typename ValueOrRange<T>::Range& r)
{
return c << r.min << r.max;
}
template <class T> Catcher& operator<<(Catcher& c, const ValueOrRange<T>& v)
{
return c << v.range << v.value;
}
int main(int argc, char *argv[])
{
ValueOrRange<std::string> vor1{{}, "bleh"};
ValueOrRange<float> vor2{{0.f, 1.f}, 0.5f};
Catcher c;
c << vor1; // works fine, displays "bleh"
c << vor2; // fails the assert in Catcher::add(const T&, priority0) with T = ValueOrRange<float>::Range
return 0;
}
While the line c << vor1 gets resolved correctly through the various overloads and has the intended effect, the second line c << vor2 fails the assert.
What I want to happen : c << vor2 calls Catcher& operator<<(Catcher& s, const ValueOrRange<float>& v), which in turn calls Catcher& operator<<(Catcher& s, const typename ValueOrRange<float>::Range& r)
What does happen : instead of Catcher& operator<<(Catcher& s, const typename ValueOrRange<float>::Range& r), it is Catcher& Catcher::operator<<(const T& v) with T = typename ValueOrRange<float>::Range that is called, and thus the assert fails.
Worthy of note is that this same code has the intended effect on MSVC, and fails the assert on GCC.
Any idea on how I should fix that ?
Thanks to feedback from Igor Tandetnik, I got rid of the ::Range-specific overload and simply went for checking std::is_same_v<T, std::string>. A little less modular than I'd like, but it'll do the trick.
// A single function will do the trick
template <class T> Catcher& operator<<(Catcher& c, const ValueOrRange<T>& v)
{
if constexpr (std::is_same_v<T, std::string>)
c << v.range;
else
c << v.range.min << v.range.max;
return c << v.value;
}
In Catcher& operator<<(Catcher& c, const typename ValueOrRange<T>::Range& r), T in non deducible.
One work around would be friend function:
template <class T> struct ValueOrRange
{
struct Range
{
T min;
T max;
friend Catcher& operator<<(Catcher& c, const Range& r)
{
return c << r.min << r.max;
}
};
Range range;
T value;
};
Demo

C++ Templated function specialization with template

I have a templated function meant to work with STL containers. However, I'd like to specialize this function for a templated class. How might I go about doing this? I'm stuck on C++11.
Edit: Updated code example. It appears to work when F is a POD like int, but is broken in the below code example where F is a class.
#include <vector>
#include <iostream>
template <class F>
class Temp {
private:
F f;
public:
Temp(F f) : f(f) {}
};
template <typename C, typename F>
struct MyClass {
MyClass (const C& c, const F& f) { }
operator C() const
{ return {}; }
};
// Base Template Function
template <typename C, typename F>
MyClass<C, F> operator| (const C & left, const F & right)
{
std::cout << "Generic version" << std::endl;
return MyClass<C, F>(left, right);
}
// Overload that I tried (ignored and used base template function instead)
template <typename C, typename F>
MyClass<C, F> operator| (const MyClass<C, F> & left, const F & right)
{
std::cout << "MyClass overload" << std::endl;
return MyClass<C, F>(C(left), right);
}
template <class F>
Temp<F> filter(F f) {
return Temp<F>(f);
}
int main ()
{
std::vector<int> v0 = { 1, 2, 3 };
auto m0 = v0
| filter([] (int i) {return i > 0;});
auto m1 = m0
| filter([] (int i) {return i < 3;});
return 0;
}
The above code example prints Generic version twice.
You can't partially specialize a template function.
But your overload should works.
I've modified your MyClass class to make it compile but, in the following example, the overload version is in charge.
#include <iostream>
template <typename C, typename F>
struct MyClass
{
template <typename ... Ts>
MyClass (Ts const & ...)
{ }
operator C() const
{ return {}; }
};
/* Base Template Function */
template <typename C, typename F>
MyClass<C, F> operator| (C const & left, F const & right)
{
std::cout << "Generic version" << std::endl;
return MyClass<C, F>(left, right);
}
/* Overload that I tried (ignored and used base template function instead) */
template <typename C, typename F>
MyClass<C, F> operator| (MyClass<C, F> const & left, F const & right)
{
std::cout << "MyClass overload" << std::endl;
return MyClass<C, F>(C(left), right);
}
int main ()
{
MyClass<int, int> m0;
auto x = m0 | 0;
static_assert( std::is_same_v<decltype(x), MyClass<int, int>>, "!" );
}

Overload template member function over any container of A or B

I have 2 existing classes A and B. I want to implement a third struct C such that C implement operator() which would take any container of A or using a different implementation any container of B. Is it possible to do a such thing using template specialization ?
enable_if is very useful in lots of scenarios, but in cases like these I'm usually more inclined to use tag dispatching. To my eye, the code looks cleaner, behaves more predictably, and if you try to use it wrongly, the error messages make slightly more sense.
struct C
{
template <class T>
void operator()(const T& container) const
{
operator()(container, Tag<typename T::value_type>());
}
private:
template <class V> struct Tag {};
template <class T>
void operator()(const T& container, Tag<A>) const
{
std::cout << "A\n";
}
template <class T>
void operator()(const T& container, Tag<B>) const
{
std::cout << "B\n";
}
};
int main()
{
std::vector<A> a;
std::list<B> b;
C c;
c(a);
c(b);
}
You can do this using template template parameters.
Assuming your containers have two parameters (content type and allocator):
class A {};
class B {};
struct C {
template <
template <
typename,
typename
>
class V
>
void operator()(const V<A, std::allocator<A> >& /* ca */) const {
}
template <
template <
typename,
typename
>
class V
>
void operator()(const V<B, std::allocator<B> >& /* cb */) const {
}
};
Which would then allow you to do the following:
int main() {
std::vector<A> va;
std::vector<B> vb;
std::list<A> la;
std::list<B> lb;
C c;
c(va);
c(la);
c(vb);
c(lb);
}
Overloads using std::enable_if and std::is_same seem to work. Not very pretty though. Note that these are c++11 features.
struct A {};
struct B {};
struct C {
template<class Cont>
void operator()(const Cont& c, typename std::enable_if<std::is_same<typename Cont::value_type, A>::value>::type * = NULL) const {
std::cout << "a";
}
template<class Cont>
void operator()(const Cont& c, typename std::enable_if<std::is_same<typename Cont::value_type, B>::value>::type * = NULL) const {
std::cout << "b";
}
};
int main() {
std::vector<A> a;
std::list<B> b;
C c;
c(a);
c(b);
}
Yes it should be possible. Arkanosis has a good solution but here is if you want to use template specialization:
class A {};
class B {};
template <template <typename , typename > class Z, class Elem> struct C
{
void operator()(const Z<Elem, std::allocator<Elem>>& v) { std::cout << "General implement" << std::endl; }
};
template <template <typename, typename > class Z> struct C<Z,B>
{
void operator()(const Z<B, std::allocator<B>>& v) { std::cout << "Specialized implement" << std::endl; }
};
Then some client code:
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char** argv)
{
std::vector<A> as;
std::list<B> bs;
C<vector,A> ca;
ca(as);
C<list,B> cb;
cb(bs);
}
If you want to handle different container types from the same C-style class you can derive from templates of the C struct e.g. class MultiContainerHandlerForA : public C<vector,A>, public C<list,A>.

generalized sorting function and using binary_function

template<class T>
struct gSorting : public std::binary_function<T, T,bool> {
bool operator() (int number, int n2)
{
cout << "int" << endl;
return (number<n2);
}
bool operator() (double number, double n2)
{
cout << "double" << endl;
return (number<n2);
}
bool operator() (const MYClass& obj1, const MYClass& obj2)
{
return (obj1.element<obj2.element);
}
};
int main () {
gSorting<int> sorting_object;
std::cout << std::boolalpha << sorting_object (2.0f, 4.3f) << ".\n";
std::getchar();
return 0;
}
is there any problem with this code? is it that generic? or is there better way to do a generic sorting algorithm to include all of my classes used
it compiles, the output pointed to the double which is good, however how can I make it a template, but dont have to specify the input type in the declaration?
gSorting< int > sorting_object;
-------------^^^^ we dont need any specific type? am I right
output:
I would personally define a class template for the binary predicate and specialize it as needed, e.g.:
template <typename T>
struct gSorting
: std::binary_function<T const&, T const&, bool> // not really needed
{
bool operator()(T const& t0, T const& t1) const {
return t0 < t1;
}
};
template <>
struct gSorting<MyClass>
: std::binary_function<MyClass const&, MyClass const&, bool>
{
bool operator()(MyClass const& c0, MyClass const& c1) const {
return c0.element < c1.element;
}
};
In a real implementation, the argument type for the generic version should probably decide whether the argument is passed by value or by const& depending on the kind of type and/or based on a trait which is then specialized as needed. For example:
template <typename T>
struct argument_type
{
typedef typename std::conditional<
std::is_fundamental<T>::value, T, T const&>::type type;
};
template <typename T>
struct gSorting
: std::binary_function<typename argument_type<T>::type,
typename argument_type<T>::type, bool>
{
typedef typename argument_type<T>::type arg_type;
bool operator()(arg_type t0, arg_type t1) const {
return t0 < t1;
}
};

How do I determine if a type is callable with only const references?

I want to write a C++ metafunction is_callable<F, Arg> that defines value to be true, if and only if the type F has the function call operator of the form SomeReturnType operator()(const Arg &). For example, in the following case
struct foo {
void operator(const int &) {}
};
I want is_callable<foo, int &> to be false and is_callable<foo, const int &> to be true. This is what I have so far :
#include <memory>
#include <iostream>
template<typename F, typename Arg>
struct is_callable {
private:
template<typename>
static char (&test(...))[2];
template<unsigned>
struct helper {
typedef void *type;
};
template<typename UVisitor>
static char test(
typename helper<
sizeof(std::declval<UVisitor>()(std::declval<Arg>()), 0)
>::type
);
public:
static const bool value = (sizeof(test<F>(0)) == sizeof(char));
};
struct foo {
void operator()(const int &) {}
};
using namespace std;
int main(void)
{
cout << is_callable<foo, int &>::value << "\n";
cout << is_callable<foo, const int &>::value << "\n";
return 0;
}
This prints 1 and 1, but I want 0 and 1 because foo only defines void operator()(const int &).
After hours of playing around and some serious discussions in the C++ chat room, we finally got a version that works for functors with possibly overloaded or inherited operator() and for function pointers, based on #KerrekSB's and #BenVoigt's versions.
#include <utility>
#include <type_traits>
template <typename F, typename... Args>
class Callable{
static int tester[1];
typedef char yes;
typedef yes (&no)[2];
template <typename G, typename... Brgs, typename C>
static typename std::enable_if<!std::is_same<G,C>::value, char>::type
sfinae(decltype(std::declval<G>()(std::declval<Brgs>()...)) (C::*pfn)(Brgs...));
template <typename G, typename... Brgs, typename C>
static typename std::enable_if<!std::is_same<G,C>::value, char>::type
sfinae(decltype(std::declval<G>()(std::declval<Brgs>()...)) (C::*pfn)(Brgs...) const);
template <typename G, typename... Brgs>
static char sfinae(decltype(std::declval<G>()(std::declval<Brgs>()...)) (G::*pfn)(Brgs...));
template <typename G, typename... Brgs>
static char sfinae(decltype(std::declval<G>()(std::declval<Brgs>()...)) (G::*pfn)(Brgs...) const);
template <typename G, typename... Brgs>
static yes test(int (&a)[sizeof(sfinae<G,Brgs...>(&G::operator()))]);
template <typename G, typename... Brgs>
static no test(...);
public:
static bool const value = sizeof(test<F, Args...>(tester)) == sizeof(yes);
};
template<class R, class... Args>
struct Helper{ R operator()(Args...); };
template<typename R, typename... FArgs, typename... Args>
class Callable<R(*)(FArgs...), Args...>
: public Callable<Helper<R, FArgs...>, Args...>{};
Live example on Ideone. Note that the two failing tests are overloaded operator() tests. This is a GCC bug with variadic templates, already fixed in GCC 4.7. Clang 3.1 also reports all tests as passed.
If you want operator() with default arguments to fail, there is a possible way to do that, however some other tests will start failing at that point and I found it as too much hassle to try and correct that.
Edit: As #Johannes correctly notes in the comment, we got a little inconsistency in here, namely that functors which define a conversion to function pointer will not be detected as "callable". This is, imho, pretty non-trivial to fix, as such I won't bother with it (for now). If you absolutely need this trait, well, leave a comment and I'll see what I can do.
Now that all this has been said, IMHO, the idea for this trait is stupid. Why whould you have such exact requirements? Why would the standard is_callable not suffice?
(Yes, I think the idea is stupid. Yes, I still went and built this. Yes, it was fun, very much so. No, I'm not insane. Atleast that's what I believe...)
(with apologies to Kerrek for using his answer as a starting point)
EDIT: Updated to handle types without any operator() at all.
#include <utility>
template <typename F, typename Arg>
struct Callable
{
private:
static int tester[1];
typedef char yes;
typedef struct { char array[2]; } no;
template <typename G, typename Brg>
static char sfinae(decltype(std::declval<G>()(std::declval<Brg>())) (G::*pfn)(Brg)) { return 0; }
template <typename G, typename Brg>
static char sfinae(decltype(std::declval<G>()(std::declval<Brg>())) (G::*pfn)(Brg) const) { return 0; }
template <typename G, typename Brg>
static yes test(int (&a)[sizeof(sfinae<G,Brg>(&G::operator()))]);
template <typename G, typename Brg>
static no test(...);
public:
static bool const value = sizeof(test<F, Arg>(tester)) == sizeof(yes);
};
struct Foo
{
int operator()(int &) { return 1; }
};
struct Bar
{
int operator()(int const &) { return 2; }
};
struct Wazz
{
int operator()(int const &) const { return 3; }
};
struct Frob
{
int operator()(int &) { return 4; }
int operator()(int const &) const { return 5; }
};
struct Blip
{
template<typename T>
int operator()(T) { return 6; }
};
struct Boom
{
};
struct Zap
{
int operator()(int) { return 42; }
};
#include <iostream>
int main()
{
std::cout << "Foo(const int &): " << Callable<Foo, int const &>::value << std::endl
<< "Foo(int &): " << Callable<Foo, int &>::value << std::endl
<< "Bar(const int &): " << Callable<Bar, const int &>::value << std::endl
<< "Bar(int &): " << Callable<Bar, int &>::value << std::endl
<< "Zap(const int &): " << Callable<Zap , const int &>::value << std::endl
<< "Zap(int&): " << Callable<Zap , int &>::value << std::endl
<< "Wazz(const int &): " << Callable<Wazz, const int &>::value << std::endl
<< "Wazz(int &): " << Callable<Wazz, int &>::value << std::endl
<< "Frob(const int &): " << Callable<Frob, const int &>::value << std::endl
<< "Frob(int &): " << Callable<Frob, int &>::value << std::endl
<< "Blip(const int &): " << Callable<Blip, const int &>::value << std::endl
<< "Blip(int &): " << Callable<Blip, int &>::value << std::endl
<< "Boom(const int &): " << Callable<Boom, const int &>::value << std::endl
<< "Boom(int&): " << Callable<Boom, int &>::value << std::endl;
}
Demo: http://ideone.com/T3Iry
Here's something I hacked up which may or may not be what you need; it does seem to give true (false) for (const) int &...
#include <utility>
template <typename F, typename Arg>
struct Callable
{
private:
typedef char yes;
typedef struct { char array[2]; } no;
template <typename G, typename Brg>
static yes test(decltype(std::declval<G>()(std::declval<Brg>())) *);
template <typename G, typename Brg>
static no test(...);
public:
static bool const value = sizeof(test<F, Arg>(nullptr)) == sizeof(yes);
};
struct Foo
{
int operator()(int &) { return 1; }
// int operator()(int const &) const { return 2; } // enable and compare
};
#include <iostream>
int main()
{
std::cout << "Foo(const int &): " << Callable<Foo, int const &>::value << std::endl
<< "Foo(int &): " << Callable<Foo, int &>::value << std::endl
;
}
Something like this maybe? It's a bit round about to make it work on VS2010.
template<typename FPtr>
struct function_traits_impl;
template<typename R, typename A1>
struct function_traits_impl<R (*)(A1)>
{
typedef A1 arg1_type;
};
template<typename R, typename C, typename A1>
struct function_traits_impl<R (C::*)(A1)>
{
typedef A1 arg1_type;
};
template<typename R, typename C, typename A1>
struct function_traits_impl<R (C::*)(A1) const>
{
typedef A1 arg1_type;
};
template<typename T>
typename function_traits_impl<T>::arg1_type arg1_type_helper(T);
template<typename F>
struct function_traits
{
typedef decltype(arg1_type_helper(&F::operator())) arg1_type;
};
template<typename F, typename Arg>
struct is_callable : public std::is_same<typename function_traits<F>::arg1_type, const Arg&>
{
}
Here is a possible solution that utilizes an extra test to see if your template is being instantiated with a const T&:
#include <memory>
#include <iostream>
using namespace std;
template<typename F, typename Arg>
struct is_callable {
private:
template<typename>
static char (&test(...))[2];
template<bool, unsigned value>
struct helper {};
template<unsigned value>
struct helper<true, value> {
typedef void *type;
};
template<typename T>
struct is_const_ref {};
template<typename T>
struct is_const_ref<T&> {
static const bool value = false;
};
template<typename T>
struct is_const_ref<const T&> {
static const bool value = true;
};
template<typename UVisitor>
static char test(typename helper<is_const_ref<Arg>::value,
sizeof(std::declval<UVisitor>()(std::declval<Arg>()), 0)>::type);
public:
static const bool value = (sizeof(test<F>(0)) == sizeof(char));
};
struct foo {
void operator()(const int &) {}
};
int main(void)
{
cout << is_callable<foo, int &>::value << "\n";
cout << is_callable<foo, const int &>::value << "\n";
return 0;
}
Ran across this while doing something else, was able to adapt my code to fit. It has the same features (and limitations) as #Xeo, but does not need sizeof trick/enable_if. The default parameter takes the place of needing to do the enable_if to handle template functions. I tested it under g++ 4.7 and clang 3.2 using the same test code Xeo wrote up
#include <type_traits>
#include <functional>
namespace detail {
template<typename T, class Args, class Enable=void>
struct call_exact : std::false_type {};
template<class...Args> struct ARGS { typedef void type; };
template<class T, class ... Args, class C=T>
C * opclass(decltype(std::declval<T>()(std::declval<Args>()...)) (C::*)(Args...)) { }
template<class T, class ... Args, class C=T>
C * opclass(decltype(std::declval<T>()(std::declval<Args>()...)) (C::*)(Args...) const) { }
template<typename T, class ... Args>
struct call_exact<T, ARGS<Args...>,
typename ARGS<
decltype(std::declval<T&>()(std::declval<Args>()...)),
decltype(opclass<T, Args...>(&T::operator()))
>::type
> : std::true_type {};
}
template<class T, class ... Args>
struct Callable : detail::call_exact<T, detail::ARGS<Args...>> { };
template<typename R, typename... FArgs, typename... Args>
struct Callable<R(*)(FArgs...), Args...>
: Callable<std::function<R(FArgs...)>, Args...>{};