C++ template function for derived class with std::is_base_of
Asked Answered
C

4

12

I've got problem with creating function that for given type, if it's derived from other one do something and for all other cases do something other. My code:

class BaseClass {};
class DerivedClass : public BaseClass {};

template <typename T>
void Function(typename std::enable_if<std::is_base_of<BaseClass, T>::value, T>::type && arg) {
    std::cout << "Proper";
}

template <typename T>
void Function(T && arg) {
    std::cout << "Improper";
}

void test() {
    Function(DerivedClass{});
}

For class DeriviedClass and other based on BaseClass I'd like to call function couting Proper, but it couts Improper. Any suggestions?

Carboniferous answered 7/2, 2017 at 8:47 Comment(1)
T is in non-deduced context here, move enable_if to the result type: auto Function(T) -> typename enable_if<???, void>::type.Duckboard
R
12

As mentioned in the comments to the question, SFINAE expressions won't work the way you did it.
It should be instead something like this:

template <typename T>
typename std::enable_if<std::is_base_of<BaseClass, T>::value>::type
Function(T && arg) {
    std::cout << "Proper" << std::endl;
}

template <typename T>
typename std::enable_if<not std::is_base_of<BaseClass, T>::value>::type
Function(T && arg) {
    std::cout << "Improper" << std::endl;
}

SFINAE expressions will enable or disable Function depending on the fact that BaseClass is base of T. Return type is void in both cases, for it's the default type for std::enable_it if you don't define it.
See it on coliru.

Other valid alternatives exist and some of them have been mentioned in other answers.

Rosemarie answered 7/2, 2017 at 9:5 Comment(3)
Is there possibility now to overload that function for specific type, e.g. float?Carboniferous
@Carboniferous overloaded non-template functions are preferred over template ones, thus yes (see here as an example).Rosemarie
Are you sure? en.cppreference.com/w/cpp/types/enable_if notes said me that you are wrongAnthologize
J
5
#include <typeinfo>
#include <iostream>

class BaseClass {};
class DerivedClass : public BaseClass {};
class OtherClass {};

template <typename T,typename = typename std::enable_if<std::is_base_of<BaseClass, T>::value, T>::type>
void Function(T && arg)
{
  std::cout << "Proper" << std::endl;
}

void Function(...)
{
  std::cout << "Improper"<< std::endl;
}

int main()
{
  Function(DerivedClass{});
  Function(BaseClass{});
  Function(OtherClass{});
}
Journal answered 7/2, 2017 at 9:6 Comment(1)
Function<OtherClass, void>(OtherClass{}); can be used to break it easily. Too weak a solution.Rosemarie
B
3
template <typename T>
auto Function(T && arg) -> typename std::enable_if<std::is_base_of<BaseClass, T>::value>::type 
{
    std::cout << "Proper";
}

template <typename T>
auto Function(T && arg) -> typename std::enable_if<!std::is_base_of<BaseClass, T>::value>::type 
{
    std::cout << "Improper";
}

wandbox example

Bulldoze answered 7/2, 2017 at 9:6 Comment(0)
V
1

C++11+ :

#include <type_traits> // for is_base_of<>

class Base {};
class Derived : public Base {};

class NotDerived {};

template<typename Class>
void foo(const Class& cls)
{
  static_assert(is_base_of<Base, Class>::value, "Class doesn't inherit from Base!");
  // The codes...
}

int main()
{
  foo(Derived()); // OK!
  foo(NotDerived()); // Error!

  return 0;
}
Vomitory answered 15/4, 2020 at 14:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.