In the language reference of std::enable_if
at cppreference the following note is included
Notes
A common mistake is to declare two function templates that differ only in their default template arguments. This is illegal because default template arguments are not part of function template's signature, and declaring two different function templates with the same signature is illegal.
In the template functions in example below, it seems to me that this situation occurs. I.e., the two template functions onlyForDerivedObjects(...)
seem (to me) to differ only by their default template arguments. I realize I am missing something here, and hopefully someone can explain this to me, or point me in the direction to where I might find an epiphany for myself.
typename std::enable_if ...
part in the template functions below when I consider it to yield a situation with two template functions which differ only in their default template argument?Base and derived classes:
class BaseA
{
public:
int getInt() const { return 21; };
};
class DerivedA : public BaseA {};
class BaseB
{
public:
int getAnotherInt() const { return 33; };
};
class DerivedB : public BaseB {};
with the following template functions
/* template functions that, seemingly, only differ in their
default template arguments? */
template< class T,
typename std::enable_if<std::is_base_of<BaseA, T>::value>::type* = nullptr >
int onlyForDerivedObjects(const T& obj)
{
return 2*obj.getInt();
}
template< class T,
typename std::enable_if<std::is_base_of<BaseB, T>::value>::type* = nullptr >
int onlyForDerivedObjects(const T& obj)
{
return 3*obj.getAnotherInt();
}
compiles and runs fine (g++ -Wall -std=c++11 ...
, g++ 4.9.3
)
#include <iostream>
#include <type_traits>
/* ... classes and template functions as above */
/* template argument deduction seems to work fine */
int main()
{
DerivedA* objA = new DerivedA();
DerivedB* objB = new DerivedB();
std::cout << onlyForDerivedObjects(*objA) << std::endl; // 42
std::cout << onlyForDerivedObjects(*objB) << std::endl; // 99
return 0;
}
In C++ metaprogramming, std::enable_if is an important function to enable certain types for template specialization via some predicates known at the compile time. Using types that are not enabled by std::enable_if for template specialization will result in compile-time error.
Template parameters may have default arguments. The set of default template arguments accumulates over all declarations of a given template.
A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)
A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.
Notes
A common mistake is to declare two function templates that differ only in their default template arguments. This is illegal because default template arguments are not part of function template's signature, and declaring two different function templates with the same signature is illegal.
Your functions don't differ only in their default template arguments, they differ in their template parameters, so have different signatures.
In both cases the default template argument is nullptr
, but the second template parameter is different in each case.
The common mistake is:
template <typename T, typename = std::enable_if_t<cond>>
void foo()
template <typename T, typename = std::enable_if_t<!cond>>
void foo()
which both declare
template <typename, typename>
void foo();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With