I want to create an overloaded template, that runs a function Foo() if a class contains it, else it does nothing.
class A
{
public:
template <typename U>
void Foo(U& u)
{
std::cout << "Has Foo()" << std::endl;
// Modify u
}
};
class B
{
// Does not contain Foo()
};
I've been trying to run it as such
template <typename T, typename U>
decltype(std::declval<T>().Foo()) TriggerFoo(T* t, U& u)
{
t->Foo(u);
}
template <typename T, typename U>
void TriggerFoo(T* t, U& u)
{
std::cout << "Does not have Foo()" << std::endl;
}
int main()
{
A a;
B b;
U u; // Some type
TriggerFoo<A, U>(&a, u); // I want to print "Has Foo()".
TriggerFoo<B, U>(&b, u); // Prints "Does not have Foo()".
return 0;
}
At the moment, both classes are passed to the "Does not have Foo()" instantiation. It compiles, but obviously it doesn't work, and it is most probably because I don't understand declval well enough. I have also tried with non-template functions and it still does not work.
Any help will be greatly appreciated.
There were two basic issues with your approach:
decltype(std::declval<T>().Foo())
This will never be succesfully resolved, because the Foo() in question will always take a parameter. This part should be:
decltype(std::declval<T>().Foo(std::declval<U &>()))
But now you will run into a different problem: when the class implements Foo(), the template resolution will become ambiguous. Either template function can be used.
So, you need another level of indirection, and templates of different priorities:
#include <iostream>
#include <type_traits>
class A
{
public:
template <typename U>
void Foo(U& u)
{
std::cout << "Has Foo()" << std::endl;
// Modify u
}
};
class B
{
// Does not contain Foo()
};
template <typename T, typename U, typename Z=decltype(std::declval<T>().Foo(std::declval<U &>()))>
void DoTriggerFoo(T* t, U& u, int dummy)
{
t->Foo(u);
}
template <typename T, typename U>
void DoTriggerFoo(T* t, U& u, ...)
{
std::cout << "Does not have Foo()" << std::endl;
}
template <typename T, typename U>
void TriggerFoo(T *t, U &u)
{
DoTriggerFoo(t, u, 0);
}
class U {};
int main()
{
A a;
B b;
U u; // Some type
TriggerFoo<A, U>(&a, u); // I want to print "Has Foo()".
TriggerFoo<B, U>(&b, u); // Prints "Does not have Foo()".
return 0;
}
Results with gcc 5.3:
$ ./t
Has Foo()
Does not have Foo()
P.S.:
std::declval<T &>().Foo(std::declval<U &>())
It's possible that this will work better, with your actual classes.
Extension to Sam's answer, if you aren't using pointers you can simplify the code further which makes it look a bit neater.
#include <iostream>
#include <type_traits>
class A
{
public:
template <typename U>
void Foo(U& u)
{
std::cout << "Has Foo()\n";
}
};
class B
{
// Does not contain Foo()
};
template <
typename T,
typename U,
typename Z=decltype(std::declval<T>().Foo(std::declval<U&>()))>
void TriggerFoo(T& t, U& u)
{
t.Foo(u);
}
template <typename... T>
void TriggerFoo(const T&...)
{
std::cout << "Does not have Foo()\n";
}
class U {};
int main()
{
A a;
B b;
U u;
TriggerFoo<A, U>(a, u); // I want to print "Has Foo()".
TriggerFoo<B, U>(b, u); // Prints "Does not have Foo()".
return 0;
}
Related
I am trying to write a method hello() that is conditionally generated based on whether the some typename P can be constructed from P{Ptr<int>, Ptr<int>} using braces initializers, (where Ptr<int> wraps an int* and has a conversion operator to handle P{int*, int*}).
The below code works in C++ (https://godbolt.org/z/rMvzxbPWx), but not with NVCC, (https://godbolt.org/z/WGoP4aEK1).
#include <tuple>
#include <iostream>
#include <type_traits>
template<class U, typename... A>
constexpr decltype(void(U{ std::declval<A>()... }), std::true_type{}) is_braces_constructible_test(int) { return std::true_type{}; }
template<class U, typename... A>
constexpr std::false_type is_braces_constructible_test(...) { return std::false_type{}; }
template<typename U, typename Tu, typename = void>
struct is_braces_constructible { };
template<typename U, template<typename...> class Tu, typename ...A>
struct is_braces_constructible<U, Tu<A...>> {
constexpr static bool value = is_braces_constructible_test<U, A...>(0);
};
template<typename T>
struct Ptr {
T* ptr;
operator T* () { return ptr; }
};
struct Point {
int* x;
int* y;
};
template<typename U>
constexpr bool is_constructable_from_tuple() {
return is_braces_constructible<U, std::tuple<Ptr<int>, Ptr<int>>>::value;
}
template<typename P>
typename std::enable_if<is_constructable_from_tuple<P>(), void>::type hello()
{
std::cout << "P is constructible from std::tuple<Ptr<int>, Ptr<int>>" << std::endl;
}
int main() {
hello<Point>();
std::cout << is_constructable_from_tuple<Point>() << std::endl;
return 0;
}
But when I comment out the hello<Point>() line, the code compiles, and it outputs that is_constructable_from_tuple<Point>() == 1.
This strange, because is_constructable_from_tuple<Point>() is the condition that is used in the enable_if for the hello<Point>() method. It almost feels like at compile-time, is_constructable_from_tuple<Point>() evaluates to 0, but at runtime it evaluates to 1?
The code compiles if Point has the constructor Point(int*, int*){} but this is not required in C++.
I tried using specialization of classes instead of method specialization, and seems to work when the default/dummy-class has the same method signature. On my computer it prints "SFIANE WORKED".
(https://godbolt.org/z/Gv41ob8Gq)
template<typename U>
constexpr bool is_constructable_from_tuple() {
return is_braces_constructible<U, std::tuple<Ptr<int>, Ptr<int>>>::value;
}
template<typename P, typename = void>
struct Hello {
void hello() {
std::cout << "SFINAE ERROR" << std::endl;
}
};
template<typename P>
struct Hello<P, typename std::enable_if<is_constructable_from_tuple<P>()>::type> {
void hello() {
std::cout << "SFINAE WORKED" << std::endl;
}
};
int main() {
Hello<Point>().hello();
return 0;
}
But when I change it to this:
template<typename P, typename = void>
struct Hello {
};
template<typename P>
struct Hello<P, typename std::enable_if<is_constructable_from_tuple<P>()>::type> {
void hello() {
std::cout << "SFINAE WORKED" << std::endl;
}
};
It does not compile in NVCC (https://godbolt.org/z/68c3WY397), but compiles in C++ (https://godbolt.org/z/8hTEaEWad).
Additionally, on my computer, if I change the method in the specialized class to be ‘T hello()’, then it does not compile unless I also change the default class to ‘T hello()’, even though at runtime I can see from the console output that it’s returning a Point constructed from the specialized class and not the default class.
It seems like I can try returning std::declval() in the default SFINAE class that I'm not using.
For example, given the following code
class A {
public:
double operator()(double foo) {
return foo;
}
};
class B {
public:
double operator()(double foo, int bar) {
return foo + bar;
}
};
I want to write two versions of fun, one that works with objects with A's signature and another one that works with objects with B's signature:
template <typename F, typename T>
T fun(F f, T t) {
return f(t);
}
template <typename F, typename T>
T fun(F f, T t) {
return f(t, 2);
}
And I expect this behavior
A a();
B b();
fun(a, 4.0); // I want this to be 4.0
fun(b, 4.0); // I want this to be 6.0
Of course the previous example throws a template redefinition error at compile time.
If B is a function instead, I can rewrite fun to be something like this:
template <typename T>
T fun(T (f)(T, int), T t) {
return f(t, 2);
}
But I want fun to work with both, functions and callable objects. Using std::bind or std::function maybe would solve the problem, but I'm using C++98 and those were introduced in C++11.
Here's a solution modified from this question to accommodate void-returning functions. The solution is simply to use sizeof(possibly-void-expression, 1).
#include <cstdlib>
#include <iostream>
// like std::declval in c++11
template <typename T>
T& decl_val();
// just use the type and ignore the value.
template <std::size_t, typename T = void>
struct ignore_value {typedef T type;};
// This is basic expression-based SFINAE.
// If the expression inside sizeof() is invalid, substitution fails.
// The expression, when valid, is always of type int,
// thanks to the comma operator.
// The expression is valid if an F is callable with specified parameters.
template <class F>
typename ignore_value<sizeof(decl_val<F>()(1),1), void>::type
call(F f)
{
f(1);
}
// Same, with different parameters passed to an F.
template <class F>
typename ignore_value<sizeof(decl_val<F>()(1,1),1), void>::type
call(F f)
{
f(1, 2);
}
void func1(int) { std::cout << "func1\n"; }
void func2(int,int) { std::cout << "func2\n"; }
struct A
{
void operator()(int){ std::cout << "A\n"; }
};
struct B
{
void operator()(int, int){ std::cout << "B\n"; }
};
struct C
{
void operator()(int){ std::cout << "C1\n"; }
void operator()(int, int){ std::cout << "C2\n"; }
};
int main()
{
call(func1);
call(func2);
call(A());
call(B());
// call(C()); // ambiguous
}
Checked with gcc and clang in c++98 mode.
I am trying to write a pair of overloaded functions, one that must be called for a pointer to a type that is not a B or a child of B, and the second must be called for pointers to B and children of B. At first I tried to use specialization of the template for B, but this doesn't work for derived classes of B. So I looked up SFINAE and enable_if etc but couldn't get it to work.
The signature of the generic function is
(1) template<typename T> int f(T *t)
For the other I tried to use enable_if and is_base_of like so:
(2) template<typename T> int f(typename enable_if<is_base_of<B, T>::value, T>::type *t)
but always (1) gets called. I tried to replace (1) by the negation of (2):
(1b) template<typename T> int f(typename enable_if<!is_base_of<B, T>::value, T>::type *t)
and now I get errors for all Ts whether or not they are (children of) B.
What am I doing wrong? What is the solution?
Test code is as follows:
#include <type_traits>
#include <iostream>
using namespace std;
class B {};
class D : public B {};
class C {};
// (1)
/* template<typename T>
int f(T *t)
{ cout << "T\n"; } */
// (1b)
template<typename T>
int f(typename enable_if<!is_base_of<B, T>::value, T>::type *t)
{ cout << "T\n"; }
// (2)
template<typename T>
int f(typename enable_if<is_base_of<B, T>::value, T>::type *t)
{ cout << "B\n"; }
int main()
{
B b;
D d;
C c;
f(&b); // Want B; get T with (1), dont compile with (1b)
f(&d); // Want B; get T with (1), dont compile with (1b)
f(&c); // Want T; get T with (1), dont compile with (1b)
return 0;
}
Moving the SFINAE into the template parameters we can use
// if not B or a descendant
template<typename T, typename enable_if<!is_base_of<B, T>::value>::type* = nullptr>
void f(T *t)
{ cout << "T\n"; }
// only if B or a descendant
template<typename T, typename enable_if<is_base_of<B, T>::value>::type* = nullptr>
void f(T *t)
{ cout << "B\n"; }
And then running it against
int main()
{
B b;
D d;
C c;
f(&b); // Want B; get T with (1), dont compile with (1b)
f(&d); // Want B; get T with (1), dont compile with (1b)
f(&c); // Want T; get T with (1), dont compile with (1b)
return 0;
}
We get
B
B
T
Live Example
I also made the functions void functions since you did not have any return statements.
typename enable_if<!is_base_of<B, T>::value, T>::type is non deducible, so you have to call explicitly:
f<B>(&b); // Want B;
f<D>(&d); // Want B;
f<C>(&c); // Want T;
Demo
To be deducible, you may use SFINAE with one of the classical way: return type
// (1b)
template<typename T>
enable_if_t<!is_base_of<B, T>::value>
f(T* t)
{ cout << "T\n"; }
// (2)
template<typename T>
enable_if_t<is_base_of<B, T>::value>
f(T* t)
{ cout << "B\n"; }
Demo
or as template parameter:
// (1b)
template<typename T, enable_if_t<!is_base_of<B, T>::value>* = nullptr>
void f(T* t)
{ cout << "T\n"; }
// (2)
template<typename T, enable_if_t<is_base_of<B, T>::value>* = nullptr>
void f(T* t)
{ cout << "B\n"; }
Demo
A very simple workaround is to pass the pointer again as a second function argument that is used to discriminate between the two versions
template<typename T>
void fImpl(T* t, const void*) {
std::cout << "general";
}
template<typename T>
void fImpl(T *b, const B*) {
std::cout << "specific";
}
template<typename T>
void f(T *t) {
fImpl(t, t);
}
In case when static polymorphism is used, especially in templates (e.g. with policy/strategy pattern), it may be required to call base function member, but you don't know was instantiated class actually derived from this base or not.
This easily can be solved with old good C++ ellipsis overload trick:
#include <iostream>
template <class I>
struct if_derived_from
{
template <void (I::*f)()>
static void call(I& x) { (x.*f)(); }
static void call(...) { }
};
struct A { void reset() { std::cout << "reset A" << std::endl; } };
struct B { void reset() { std::cout << "reset B" << std::endl; } };
struct C { void reset() { std::cout << "reset C" << std::endl; } };
struct E: C { void reset() { std::cout << "reset E" << std::endl; } };
struct D: E {};
struct X: A, D {};
int main()
{
X x;
if_derived_from<A>::call<&A::reset>(x);
if_derived_from<B>::call<&B::reset>(x);
if_derived_from<C>::call<&C::reset>(x);
if_derived_from<E>::call<&E::reset>(x);
return 0;
}
The question is:
Is there any better simple way (e.g. SFINAE doesn't look so) to achieve same result in C++11/C++14?
Would empty call of ellipsis parameter function be elided by optimizing compiler? Hope such case is not special against any "normal" function.
One option is to introduce two overloads of different priorities and to equip the preferred one with an expression SFINAE.
#include <utility>
template <typename T, typename... Args, typename C, typename R, typename... Params>
auto call_impl(int, R(C::*f)(Args...), T&& t, Params&&... params)
-> decltype((std::forward<T>(t).*f)(std::forward<Params>(params)...))
{
return (std::forward<T>(t).*f)(std::forward<Params>(params)...);
}
template <typename T, typename... Args, typename C, typename R, typename... Params>
void call_impl(char, R(C::*)(Args...), T&&, Params&&...)
{
}
template <typename T, typename... Args, typename C, typename R, typename... Params>
auto call(R(C::*f)(Args...), T&& t, Params&&... params)
-> decltype(call_impl(0, f, std::forward<T>(t), std::forward<Params>(params)...))
{
return call_impl(0, f, std::forward<T>(t), std::forward<Params>(params)...);
}
Test:
int main()
{
X x;
call(&B::reset, x);
}
DEMO
The upper function will be selected first by overload resolution (due to an exact match of 0 against int), and possibly excluded from the set of viable candidates if (t.*f)(params...) is not valid. In the latter case, the call to call_impl falls back to the second overload, which is a no-op.
Given that &A::reset may fail for multiple reasons, and you may not necessarily want to explicitly specify the function's signature, and, on top of that, you want the call to fail if the member function exists, but it does not match function call arguments, then you can exploit generic lambdas:
#include <utility>
#include <type_traits>
template <typename B, typename T, typename F
, std::enable_if_t<std::is_base_of<B, std::decay_t<T>>{}, int> = 0>
auto call(T&& t, F&& f)
-> decltype(std::forward<F>(f)(std::forward<T>(t)))
{
return std::forward<F>(f)(std::forward<T>(t));
}
template <typename B, typename T, typename F
, std::enable_if_t<!std::is_base_of<B, std::decay_t<T>>{}, int> = 0>
void call(T&& t, F&& f)
{
}
Test:
int main()
{
X x;
call<A>(x, [&](auto&& p) { return p.A::reset(); });
call<B>(x, [&](auto&& p) { return p.B::reset(); });
}
DEMO 2
what about something like:
#include <iostream>
#include <type_traits>
struct A { void reset() { std::cout << "reset A" << std::endl; } };
struct B { void reset() { std::cout << "reset B" << std::endl; } };
struct X :public A{};
template <typename T, typename R, typename BT>
typename std::enable_if<std::is_base_of<BT, T>::value, R>::type
call_if_possible(T & obj, R(BT::*mf)())
{
return (obj.*mf)();
}
template <typename T, typename R, typename BT>
typename std::enable_if<!std::is_base_of<BT, T>::value, R>::type
call_if_possible(T & obj, R(BT::*mf)()) { }
int main()
{
X x;
call_if_possible(x, &A::reset);
call_if_possible(x, &B::reset);
}
ideone
edit
maybe more readable way:
template <typename T, typename R, typename BT>
R call_if_possible_impl(T & obj, R(BT::*mf)(), std::false_type){}
template <typename T, typename R, typename BT>
R call_if_possible_impl(T & obj, R(BT::*mf)(), std::true_type)
{
return (obj.*mf)();
}
template <typename T, typename R, typename BT>
R call_if_possible(T & obj, R(BT::*mf)())
{
return call_if_possible_impl(obj, mf, typename std::is_base_of<BT, T>::type());
}
ideone
Basing on previously provided answers by #PiotrSkotnicki and #relaxxx I would like to combine the most simple and readable solution, without SFINAE and other blood-from-the-eyes things. It's just for reference, will not be accepted anyway:
#include <iostream>
#include <type_traits>
template <class Base, class Derived>
using check_base = typename std::is_base_of<Base, Derived>::type;
template <class Base, class Derived, typename Func>
void call(Derived& d, Func&& f)
{
call<Base>(d, std::forward<Func>(f), check_base<Base, Derived>());
}
template <class Base, typename Func>
void call(Base& b, Func&& f, std::true_type)
{
f(b);
}
template <class Base, class Derived, typename Func>
void call(Derived&, Func&&, std::false_type)
{
}
struct A { void reset(int i) { std::cout << "reset A: " << i << std::endl;} };
struct B { void reset() { std::cout << "reset B" << std::endl;} };
struct C { void reset() { std::cout << "reset C" << std::endl;} };
struct E: C { void reset() { std::cout << "reset E" << std::endl;} };
struct D: A, E {};
int main()
{
D d;
int i = 42;
call<A>(d, [&](auto& p) { p.reset(i); } );
call<B>(d, [](auto& p) { p.reset(); } );
call<C>(d, [](auto& p) { p.reset(); } );
call<E>(d, [](auto& p) { p.reset(); } );
}
Live at: http://cpp.sh/5tqa
In the code below, the class template uses one parameter but the function template uses two if the template argument is a template. This is ok when using type deduction but odd when using explicit template instantiation.
Is is possible to write the template template parameter as one single parameter?
This question is linked to function overload matching template template
#include <iostream>
template <typename T>
struct C
{
C (T i)
{
std::cout << "simple" << std::endl;
}
};
template <template<typename TT> class FF, typename TT>
struct C <FF<TT> > // (1)
{
C (FF<TT> i)
{
std::cout << "template" << std::endl;
}
};
template <typename T>
void F (T i)
{
std::cout << "simple" << std::endl;
}
// two template arguments FF and TT.
// Anyway to write this so that the argument count is one?
template <template<typename TT> class FF, typename TT>
void F (FF<TT> i)
{
std::cout << "template" << std::endl;
}
template <typename T>
struct R
{
T x;
};
int main()
{
R<int> r;
C<R<int> >{r}; // prints 'template', as expected
F<R<int> >(r); // prints 'simple', probably not what you think
F<R,int >(r); // prints 'template' as expected but
}
EDIT:
I came to the conclusion that the question is not a good one because if there where a one parameter syntax, the overload resolution would still pick the wrong function. This comes as a surprise to me but here is the code that proves it (same code as before except one template function overload that changed):
EDIt2: added a further print in the main skipping the explicit template specification.
EDIT3: The code below is nonsense. I made a mistake as #DyP pointed out correctly. I am calling void F(R<R<T>>) in the explicit case and not void F(R<T>) .
#include <iostream>
template <typename T>
struct R
{
T x;
};
template <typename T>
struct C
{
C (T i)
{
std::cout << "simple" << std::endl;
}
};
template <template<typename TT> class FF, typename TT>
struct C <FF<TT> > // (1)
{
C (FF<TT> i)
{
std::cout << "template" << std::endl;
}
};
template <typename T>
void F (R<T> i)
{
std::cout << "template" << i.x << std::endl;
}
template <typename T>
void F (T i)
{
std::cout << "simple" << std::endl;
}
int main()
{
R<int> r;
C<R<int> >{r}; // prints 'template', as expected
F<R<int> >(r); // prints 'simple', probably not the expected overload
F (r); // prints 'template', now overload resolution works. Strange.
}
With SFINAE:
#include <type_traits>
template<class T>
struct is_template_with_one_param
: std::false_type
{};
template<template<class> class TT, class T>
struct is_template_with_one_param< TT<T> >
: std::true_type
{};
#include <iostream>
template <typename T>
typename std::enable_if< not is_template_with_one_param<T>{}, void >::type
F (T i)
{
std::cout << "simple" << std::endl;
}
template <typename T>
typename std::enable_if< is_template_with_one_param<T>{}, void >::type
F (T i)
{
std::cout << "template" << std::endl;
}
usage example:
template <typename T>
struct R
{
T x;
};
int main()
{
F(R<int>{});
F(42);
}
Alternatively, consider Jarod42's suggestion.
Another possible solution:
#include <iostream>
template <typename T>
struct C
{
C (T i)
{
std::cout << "simple" << std::endl;
}
};
template <template<typename TT> class FF, typename TT>
struct C <FF<TT> > // (1)
{
C (FF<TT> i)
{
std::cout << "template" << std::endl;
}
};
template <typename T>
void F (T i)
{
C<T> x(i);
}
template <typename T>
struct R
{
T x;
};
int main()
{
R<int> r;
F(r);
F(4);
}