Why compile error with enable_if
Because you use enable_if
without using the template parameter T
in your function templates. If you want to specialize for when the struct S
has a certain template parameter value N
, you'll need to use class template specialization.
template <int N, class Enable = void>
struct S { };
template <int N>
struct S<N, typename std::enable_if<N == 1>::type>
{
....
};
Are these the expected errors with std::enable_if, or am I using it incorrectly?
std::enable_if_t
is a template that causes substitution to fail if the condition is false. Because of SFINAE this does not cause the program to be ill-formed, when it happens during overload resolution. You are passing it a false value as the default value, so for a call to function()
, without any additionally specified template parameters, overload resolution will fail.
If you change template <int Z = 0>
part to int Z = 1
then I would expect the code to compile.
More to the second part of the question: Are these other errors expected?
smelly_template.cpp:3:40: note: candidate: ‘template<int Z> std::enable_if_t<(Z != 0)> function()’
3 | template <int Z=0> std::enable_if_t<Z> function () { }
| ^~~~~~~~
smelly_template.cpp:3:40: note: template argument deduction/substitution failed:
In file included from smelly_template.cpp:1:
Yes, the compiler tries to help you by showing what it tried, whenever overload resolution fails. Modern versions of gcc and clang will show you every overload that was available and why it couldn't be used. In this case, it is explaining why overload resolution failed with the one overload that it tried. These kinds of errors when overload resolutions fails are extremely helpful in large programs.
compile error - templates, enable_if
You declare Citizen
to be a class template taking 5 template parameters:
template <typename T, T, T, bool, typename >
class Citizen { ... };
and then try to define the constructor using only 4 template parameters:
template <typename T, T minAge, T maxAge, bool isarmed>
Citizen<T, minAge, maxAge, isarmed>::Citizen(T health, T age)
There is no such previously declared 4-template-parameter Citizen
, hence the error. You still need that last template parameter.
Note that SFINAE here doesn't make much sense unless you have some other non-arithmetic Citizen
class template (which itself doesn't make much sense). Just have a static_assert
for T
being an arithmetic type.
Why does failed enable_if lead to compile time error?
As I understand it should lead to SFINAE
SFINAE means "substitution failure is not an error". You need substitution to occur in order to SFINAE out something. In this case, it is sufficient to add a default template parameter to your copy constructor:
template <typename D = Data>
Container(const typename std::enable_if<std::is_copy_constructible<D>::value,
self_type>::type& other_data) :
m_data(other_data.m_data)
{
}
live example on wandbox
std::enable_if is generating error when used on functions of same name inside a template class
Like @Evg mentioned you have to need the member function to be templated as well.
In addition, you need to provide default values for them, like usual nullptr
defaulting.
See a demo
#include <iostream>
#include <type_traits>
template<typename T>
class Coverage {
public:
Coverage(T type) :_type(type) {}
//signed char
template<typename Type = T> // templated the member!
int getNb(typename std::enable_if<std::is_signed<Type>::value, void>::type* = nullptr)
{
return 1;
}
//unsigned int
template<typename Type = T> // templated the member!
int getNb(typename std::enable_if<std::is_unsigned<Type>::value, void>::type* = nullptr)
{
return 2;
}
};
Or provide a trailing return SFINAE for each functions
See a demo
#include <iostream>
#include <type_traits>
template<typename T>
class Coverage {
public:
Coverage(T type) :_type(type) {}
template<typename Type = T>
auto getNb() -> typename std::enable_if<std::is_signed<Type>::value, int>::type
{
return 1;
}
template<typename Type = T>
auto getNb() -> typename std::enable_if<std::is_unsigned<Type>::value, int>::type
{
return 2;
}
private:
T _type;
};
Errors with std::enable_if
When you use std::enable_if<false, bool>::type
literally there is nothing to be substituted. Thus, the code is always wrong and the compilers reports the error as such. SFINAE only applies if there is "S" (substitution) which ended up to "F" (failure).
c++11 enable_if error
The template template< bool B, class T = void > struct enable_if
is specialized so that it only has a typedef type
when the condition B is true
.
Your compiler is correct. There is no typedef for type
in struct std::enable_if<false, void>
. There is only a typedef in struct std::enable_if<true, void>
.
For more info look here.
So to fix your problem you need to make sure that the enable_if
which has a B that evaluates to false
never gets compiled. You can achieve this with the help of SFINAE by making my_memcpy
a function template. The compiler will then not report an error when failing to compile the function template where B evaluates to false
and will successfully compile and use the function where B evaluates to true
.
#include <iostream>
#include <type_traits>
using namespace std;
struct is_64_bit
{
static const bool value = sizeof(void*) == 8;
};
template<typename T>
typename enable_if<is_64_bit::value, T>::type
my_memcpy(T* target, const T* source, size_t n)
{
cout << "64 bit memcpy" << endl;
}
template<typename T>
typename enable_if<!is_64_bit::value, T>::type
my_memcpy(T* target, const T* source, size_t n)
{
cout << "32 bit memcpy" << endl;
}
std::enable_if not compiling (invalid template argument)
The best way and the less intrusive one to do SFINAE is to use a non type template parameter:
template <class Archive, typename T,
std::enable_if_t<std::is_base_of<Serializable, T>::value, int> = 0
>
Archive &operator>>( Archive &in, std::unique_ptr<T>& ptr)
{
// ...
}
And if you want to make it shorter:
template<typename Cond>
using my_enable = std::enable_if_t<Cond::value, int>;
template<typename T>
using is_serializable = std::is_base_of<Serializable, T>;
template <class Archive, typename T, my_enable<is_serializable<T>> = 0>
Archive &operator>>( Archive &in, std::unique_ptr<T>& ptr)
{
// ...
}
It should be way less intrusive and cause less problem with type deduction.
Related Topics
Linux Ipc - Multiple Writers, Single Reader
Rvalue Reference Parameters and Template Functions
Gdb - List Source of Current Function Without Typing Its Name
How to Pass a Part of a Vector as a Function Argument
How to Control Memory Allocation Strategy in Third Party Library Code
Linux C++: Does a Return from Main() Cause a Multithreaded App to Terminate
Linux Serial Port Reading - How to Change Size of Input Buffer
Performance of Std::Function Compared to Raw Function Pointer and Void* This
How to Find How Much Memory Is Shared Between Forked Process with Copy-On-Write in Linux
Non-Const Reference May Only Be Bound to an Lvalue
How to Use a Constexpr Value in a Lambda Without Capturing It
Programmatically Counting Cache Faults
C++ Makefile on Linux with Multiple *.Cpp Files
Std::Chrono::System_Clock::Now() Considering The Os Configured Time Zone