How to conditionally define a variable in method call using SFINAE? - c++

I want to define a template class IE which provides public method(). method() calls underlying private run(), which may take arguments related to template parameters passed to IE. So:
For IE<void>, run() without arguments is executed.
For any other T in IE<T>, run(vector<T>) is executed.
I think I correctly SFINAE'd method run(), but I have problem with defining the parameter that should be passed to run. I came up with defining Extra in the presented way, but I get errors that T can't be deduced.
EDIT: I need a solution working for C++14 at most.
template<typename X=void>
class IE
{
template<typename T=void>
struct Extra;
template<typename T>
struct Extra<enable_if_t<is_void<T>::value, T>> {};
template<typename T>
struct Extra<enable_if_t<!is_void<T>::value, T>>
{
std::vector<T> ex;
};
template<typename X_=X>
void run(enable_if_t<is_void<X_>::value , Extra<X_>> x) {
cout << "In run" << endl;
}
template<typename X_ = X>
void run(enable_if_t<!is_void<X_>::value , Extra<X_>> x)
{
cout << "In run: X=" << x.ex.size() << endl;
}
public:
void method()
{
Extra<X> x;
run(x);
}
};
int main() {
IE<double> ie1;
ie1.method(); // should execute run(vector<double>)
IE<> ie2;
ie2.method(); // should execute run()
return 0;
}

From your intent, you can do it with Constexpr if (since C++17). e.g.
template<typename X=void>
class IE
{
void run() {
cout << "In run()" << endl;
}
void run(std::vector<X> x)
{
cout << "In run: X=" << x.size() << endl;
}
public:
template<typename X_ = X>
void method()
{
if constexpr (std::is_same_v<X_, void>)
run();
else
run(std::vector<X_>{...});
}
};
LIVE
Before C++17 you can apply SFINAE (or specialization), e.g.
template<typename X=void>
class IE
{
void run() {
cout << "In run()" << endl;
}
void run(std::vector<X> x)
{
cout << "In run: X=" << x.size() << endl;
}
public:
template<typename X_ = X>
std::enable_if_t<std::is_same<X_, void>::value> method()
{
run();
}
template<typename X_ = X>
std::enable_if_t<!std::is_same<X_, void>::value> method()
{
run(std::vector<X_>{...});
}
};
LIVE
For your original solution, you should apply SFINAE as
template<typename X=void>
class IE
{
template<typename T, typename = void>
struct Extra;
template<typename T>
struct Extra<T, enable_if_t<is_void<T>::value>> {};
template<typename T>
struct Extra<T, enable_if_t<!is_void<T>::value>>
{
std::vector<T> ex;
};
template<typename X_ = X>
enable_if_t<is_void<X_>::value> run(Extra<X_> x) {
cout << "In run" << endl;
}
template<typename X_ = X>
enable_if_t<!is_void<X_>::value> run(Extra<X_> x)
{
cout << "In run: X=" << x.ex.size() << endl;
}
public:
void method()
{
Extra<X> x;
run(x);
}
};
LIVE

It is your definition of Extra which is incorrect,
You might simply move it outside class and use regular specialization:
template<typename T>
struct Extra
{
std::vector<T> ex;
};
template<>
struct Extra<void> {};
Demo

It may be that the actual code is more complicated, but for the code presented in the question, providing a specialization for IE<void> is the simplest approach. Get rid of all those enable_if things, and after definition of IE add the specialization:
template <>
class IE<void> {
void run() { /* ... */ }
public:
void method() { run(); }
};
(Yes, I'm not a fan of using constexpr if to write functions that have two or more completely independent execution paths depending on some type calculus; that's far too much like #ifdef ... #elif ... #endif)

Related

Single C++ Partial Specialization for const, non-const, volatile

In the example below I can effectively strip the const, volatile and reference qualifiers and use the single specialization for shared pointers. This is solved by the adding one more level of abstraction. How could I solve this without doing so? I could I just use the specialisations and match on shared_pointer, shared_pointer const etc?
#include <iostream>
#include <type_traits>
namespace detail {
template<typename T>
struct display;
template<typename T>
struct display<std::shared_ptr<T>> {
static void apply() {
std::cout << __FUNCTION__ << std::endl;
}
};
}
template<typename T>
void display() {
detail::display<std::remove_cvref_t<T>>::apply();
}
int main() {
std::shared_ptr<int> t;
display<decltype(t)>();
return 0;
}
So I have come up with a solution which I like much better which I thought I would share.
template<typename T>
struct is_shared_pointer : std::false_type { };
template<template<typename > typename T, typename U>
struct is_shared_pointer<T<U>> : std::is_same<std::decay_t<T<U>>, std::shared_ptr<U>> {};
template<typename T, typename Enable = void>
struct display;
template<typename T>
struct display<T, std::enable_if_t<is_shared_pointer<T>::value>> {
static void apply() {
std::cout << "shared ptr: " << __FUNCTION__ << std::endl;
}
};
template<typename T>
struct display<T, std::enable_if_t<std::is_integral_v<T>>> {
static void apply() {
std::cout << "integral :" << __FUNCTION__ << std::endl;
}
};
template<typename T>
struct display<T, std::enable_if_t<std::is_void_v<T>>> {
static void apply() {
std::cout << "void: " << __FUNCTION__ << std::endl;
}
};
template<typename T>
struct display<T, std::enable_if_t<std::is_floating_point_v<T>>> {
static void apply() {
std::cout << "floating: " << __FUNCTION__ << std::endl;
}
};
int main() {
std::shared_ptr<int> t;
display<decltype(t)>();
return 0;
}
That being said, I am open to suggestions, ideas and techniques.

Override template function with abstract class

I have created a template function, defined below.
template<class T>
void func(T t){ /* do stuff */ }
I would like to overload this template in the event that T inherits from an abstract class I made.
class A {
public:
virtual void doStuff() = 0;
};
class B : public A {
virtual void doStuff(){ /* do stuff */ }
}
I have tried using template specialization (below), but it still was using the original definition.
template<>
void func(A& a){ /* do different stuff */ } // Not called by func(B())
I tried overloading it as well, and while this worked with ints, it isn't working with my base class.
func(int i){ /* do stuff with i */ } // Called by func(3)
func(A& a){ /* do different stuff */ } // Not called by func(B())
I'm guessing this has to do with C++ not wanting to implicitly cast my instance of B to an A and reference it, but I haven't been able to find anything explaining how I can fix this behavior. Since A has a pure virtual function, I can't just define func(A a). Any help would be appreciated.
Here is an example in which the behavior I'm experiencing can be reproduced.
#include <iostream>
template<class T>
void func(T t){
std::cout << "Template function called!" << std::endl;
}
class A {
public:
virtual void doStuff() = 0;
};
class B : public A{
public:
virtual void doStuff(){};
};
template<>
void func(const A& a){
std::cout << "Specialized template called!" << std::endl;
}
void func(const A& a){
std::cout << "Overload called!" << std::endl;
}
int main(){
B b{};
func(b);
return 0;
}
If you have access to C++17, then you can create a public overload that will forward to the correct function:
namespace detail {
template<class T>
void func(T t) {
std::cout << "Template function called!" << std::endl;
}
void func(A& a){
std::cout << "Overload called!" << std::endl;
}
}
template<class T>
void func(T& t) {
if constexpr (std::is_base_of_v<A, T>) {
detail::func(static_cast<A&>(t));
} else {
detail::func(t);
}
}
int main() {
B b;
func(b);
}
Otherwise you can use tag dispatching or SFINAE:
Tag dispatching:
template<class T>
void func(T t, std::false_type) {
std::cout << "Template function called!" << std::endl;
}
void func(A& a, std::true_type) {
std::cout << "Other function called!" << std::endl;
}
template<class T>
void func(T& t) {
func(t, std::is_base_of<A, T>{});
}
SFINAE:
template<class T,
std::enable_if_t<std::is_base_of_v<A, T>>* = nullptr>
void func(T t) {
std::cout << "Template function called!" << std::endl;
}
template<class T,
std::enable_if_t<!std::is_base_of_v<A, T>>* = nullptr>
void func(T& t) {
std::cout << "Other function called!" << std::endl;
}
C++20 solution
You can run the code here.
Using Concepts from C++20, we can write an inherits_from concept, and use that. Concepts allow us to constrain a template so that it only applies in situations where an expression is true.
The concept looks like this:
#include <type_traits>
template<class Derived, class Base>
concept derived_from = std::is_base_of_v<Base, Derived>;
Then, we can write the generic template and the constrained template:
struct MyBase{};
struct MyDerived : MyBase{};
// This is the generic template; using auto here is valid in C++20
void do_thing(auto const& thing) {
std::cout << "Doing thing on regular type\n";
}
//This is the template that acts on classes derived from MyBase
void do_thing(derived_from<MyBase> const& x) {
std::cout << "Doing thing on MyBase\n";
}
Because the second function declares T as following the concept inherits_from, it's more specialized, so for types that actually inherit from MyBase, it'll be selected over the generic template:
int main() {
do_thing(10); // Prints "Doing thing on regular type"
do_thing(MyBase()); // Prints "Doing thing on MyBase"
do_thing(MyDerived()); // Prints "Doing thing on MyBase"
}
C++17 solution
You can run the code here.
We can emulate the behavior of concepts using SFINAE, although this requires modifying the generic template so that it'll by ignored if T extends MyBase. The key to using SFINAE is to trigger a substitution failure if a condition is false, resulting in that overload being ignored.
In order to trigger a substitution failure, add a defaulted template argument at the end of the list of template parameters. In our case, it looks like this:
template<
class T,
// This defaulted argument triggers the substitution failure
class = std::enable_if_v</* condition */>>
In our code,
- The generic overload will be disabled if T extends MyBase
- The constrained overload will be disable if T doesn't extend MyBase
It looks like this:
struct MyBase {};
struct MyDerived : MyBase {};
template<
class T,
class = std::enable_if_t<!std::is_base_of_v<MyBase, T>>>
void do_thing(T const&) {
std::cout << "Doing thing on regular type\n";
}
// This overload is *disabled* if T doesn't inherit from MyBase
template<
class T,
// We have to have an additional defaulted template argument to distinguish between the overloads
class = void,
class = std::enable_if_t<std::is_base_of_v<MyBase, T>>>
void do_thing(T const& x) {
std::cout << "Doing thing on MyBase\n";
}
Despite the weird declaration, we can still use do_thing as though it were a regular function:
int main() {
do_thing(10);
do_thing(MyBase());
do_thing(MyDerived());
}
Backporting things to C++11
You can run the code here.
We only have to make a few minor changes to backport things to C++11. Basically,
is_base_of_v<MyBase, T> has to be replaced by is_base_of<MyBase, T>::value, and
enable_if_t</* condition */> has to be replaced by typename enable_if</* condition */>::type
B b;
func((A&)b);
I don't think you can pass a temporary here. You cannot cast B() to 'A&' because it is an rvalue and casting it to const A& makes the template version a better match.
Another options (on top of other answers) using c++11 - explicitly removing the template version if T is a subtype of B:
template<class T>
typename std::enable_if<!std::is_base_of<A, T>::value>::type
func(T& t){
std::cout << "Template function called!" << std::endl;
}
void func(const A& a){
std::cout << "Overload called!" << std::endl;
}
int main(){
func(B());
}

Template specialization using another class that implicit-converts to it

I don't know if this is possible, but I would like to understand better how this works.
Can a class implict convertsion operation be used to match a template parameter?
This is what I want to do.
#include <iostream>
template<typename T>
struct Value {
};
template<>
struct Value<int> {
static void printValue(int v) {
std::cout << v << std::endl;
}
};
struct Class1 {
int value;
};
/*
template<>
struct Value<Class1*> {
static void printValue(Class1* v) {
std::cout << v->value << std::endl;
}
};
*/
template<typename X>
struct ClassContainer {
ClassContainer(X *c) : _c(c) {}
operator X*() { return _c; }
X *_c;
};
template<typename X>
struct Value<ClassContainer<X>> {
static void printValue(ClassContainer<X> v) {
std::cout << static_cast<X*>(v)->value << std::endl;
}
};
template<typename X>
void doPrintValue(X v)
{
Value<X>::printValue(v);
}
int main(int argc, char *argv[])
{
doPrintValue(10);
Class1 *c = new Class1{ 20 };
//doPrintValue(c); // error C2039: 'printValue': is not a member of 'Value<X>'
ClassContainer<Class1> cc(c);
doPrintValue(cc);
std::cout << "PRESS ANY KEY TO CONTINUE";
std::cin.ignore();
}
ClassContainer has an implict conversion to X*. Is it possible to match ClassContainer passing only X*?
If you want the template class for pointers to behave like the template class for something else, just inherit:
template<typename T>
struct Value<T*> : Value<ClassContainer<T>> {};
It will inherit the public printValue function, which accepts a parameter that can be constructed from T*, and everything will be implicitly converted as expected.
See it all live here.

`std::enable_if` is function pointer - how?

I want to use SFINAE to enable a particular template if the user passes a function pointer as a parameter.
I have googled around but found nothing - I also tried looking at the <type_traits> documentation but couldn't find anything that resembled a is_function_ptr<T>.
By function pointer, I mean global function pointers, like TReturn(*)(TArgs...).
Below is a type trait determining if something is a function pointer and a couple of test cases. Note, that to test if something is a function pointer, you need to test if std::is_pointer<P>::value is true and if std::is_function<T>::value is true where T is P with the pointer removed. The code below just does that:
#include <type_traits>
#include <iostream>
#include <utility>
template <typename Fun>
struct is_fun_ptr
: std::integral_constant<bool, std::is_pointer<Fun>::value
&& std::is_function<
typename std::remove_pointer<Fun>::type
>::value>
{
};
template <typename Fun>
typename std::enable_if<is_fun_ptr<Fun>::value>::type
test(Fun) {
std::cout << "is a function pointer\n";
}
template <typename Fun>
typename std::enable_if<!is_fun_ptr<Fun>::value>::type
test(Fun) {
std::cout << "is not a function pointer\n";
}
void f0() {}
void f1(int) {}
void f2(int, double) {}
struct s0 { void operator()() {} };
struct s1 { void operator()(int) {} };
struct s2 { void operator()(int, double) {} };
int main()
{
int v0(0);
int* p0(&v0);
void (*p1)() = &f0;
void (**p2)() = &p1;
std::cout << "v0="; test(v0);
std::cout << "p0="; test(p0);
std::cout << "p1="; test(p1);
std::cout << "p2="; test(p2);
std::cout << "f0="; test(&f0);
std::cout << "f1="; test(&f1);
std::cout << "f2="; test(&f2);
std::cout << "s0="; test(s0());
std::cout << "s1="; test(s1());
std::cout << "s2="; test(s2());
std::cout << "l0="; test([](){});
std::cout << "l1="; test([](int){});
std::cout << "l2="; test([](int, double){});
}
No SFINAE is needed to accept a function pointer or a member function pointer. To distinguish function objects from non-callable stuff SFINAE is needed, there's probably no way around this.
#include <utility>
#include <iostream>
template <typename Ret, typename... Parm>
void moo (Ret (*fp)(Parm...))
{
std::cout << "funptr" << std::endl;
}
template <typename Ret, typename Owner, typename... Parm>
void moo (Ret (Owner::*fp1)(Parm...))
{
std::cout << "memfunptr" << std::endl;
}
template <typename Funobj, typename... Parm,
typename Ret =
decltype((std::declval<Funobj>())
(std::forward(std::declval<Parm>())...))>
void moo (Funobj functor)
{
std::cout << "funobj" << std::endl;
}
void x1() {}
struct X2 { void x2() {} };
struct X3 { void operator()(){} };
int main()
{
moo(x1);
moo(&X2::x2);
moo(X3());
}

Is it possible to write specialization for member function of a template class?

template <class T, bool flag>
class A
{
//...
void f()
{
std::cout << "false" << std::endl;
}
//...
};
template<class T>
void A<T, true>::f<T, true>()
{
std::cout << "true" << std::endl;
}
The code above is wrong and don't compile, but you get the idea of what I'm going to do. So how should I do that?
You can't specialize just one method of a class. Usually you can solve that with a template nested class on the same T.
template <class T, bool flag>
class A
{
//...
template <class Q, bool flag>
class F_Helper
{
void operator()()
{
std::cout << "false" << std::endl;
}
};
template <class Q>
class F_Helper<Q, true>
{
void operator()()
{
std::cout << "true" << std::endl;
}
};
F_Helper<T> f;
//...
};
Obviously a bit more boilerplate is needed if you do need access to the enclosing class' this pointer.
Contrary to what the other answers say, you can specialize a member function of a class template. But you need to provide all template arguments
template<>
void A<int, true>::f()
{
std::cout << "true" << std::endl;
}
What you try is not valid:
template<typename T>
void A<T, true>::f()
{
std::cout << "true" << std::endl;
}
Partially specializing a member of a class template for particular arguments of that class template is not valid, so that means "define the member function 'f' of a partial specialization of A for <T, true>". Because there is no such partial specialization, the compiler will error out.
If you cannot provide all arguments, you can overload f as follows
template <class T, bool flag>
class A
{
template<typename, bool> struct params { };
void f()
{
f(params<T, flags>());
}
template<typename U>
void f(params<U, true>) {
std::cout << "true" << std::endl;
}
template<typename U, bool flag1>
void f(params<U, flag1>) {
std::cout << "dunno" << std::endl;
}
};
You can specialize whole template class - Ideone link
#include <iostream>
template <class T, bool flag>
class A
{
//...
void f()
{
std::cout << "false" << std::endl;
}
//...
};
template<class T>
class A<T, true>
{
//...
void f()
{
std::cout << "true" << std::endl;
}
//...
};
You need to specialize the whole class:
#include <iostream>
template <class T, bool flag>
class A
{
public:
void f()
{
std::cout << "false" << std::endl;
}
};
template<class T>
class A<T,true>
{
public:
void f()
{
std::cout << "true" << std::endl;
}
};
void main()
{
A<int, false> a;
a.f();
A<int, true> b;
b.f();
}