Why does failed enable_if lead to compile time error? - c++11

I want to disable copy constructor of some template class conditionally. In other words, I want disable copy constructor, if base type is not copy constructible. To solve such problem (in educational purposes) I decided to write following program. (Here is link to ideone https://ideone.com/QY0NHJ) Below is source of my program:
#include <algorithm>
#include <type_traits>
using namespace std;
template <typename Data>
class Container
{
public:
typedef Container<Data> self_type;
Container():
m_data()
{
}
Container(const typename
std::enable_if<std::is_copy_constructible<Data>::value,
self_type>::type& other_data) :
m_data(other_data.m_data)
{
}
Container(self_type&& other)
{
std::swap(m_data, other.m_data);
}
private:
Data m_data;
};
class SomeData
{
public:
SomeData(){}
SomeData(const SomeData&) = delete;
};
int main()
{
Container<SomeData> container;
return 0;
}
But message from compiler really confuses me:
prog.cpp: In instantiation of ‘class Container’:
prog.cpp:41:22: required from here
prog.cpp:17:2: error: no type named ‘type’ in ‘struct std::enable_if >’
Container(const typename std::enable_if::value
As I understand it should lead to SFINAE and nothing should be arised from compiler. Where am I wrong?

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

Related

CRTP traits only working with templated derived class

I have seen an idiom for using Derived type traits in the base class of a CRTP pattern that looks like this:
template<typename Derived>
struct traits;
template<typename Derived>
struct Base {
using size_type = typename traits<Derived>::size_type;
};
template <typename T>
struct Derived1 : Base<Derived1<T>>{
using size_type = size_t;
void print(){ std::cout << "Derived1" << std::endl; }
};
template <typename T>
struct traits<Derived1<T>> {
using size_type = size_t;
};
int main()
{
using T = float;
Derived1<T> d1;
d1.print();
}
My understanding is that the purpose of the idiom is to delay the instantiation of the Base class's size_type. What I am confused by is the fact that this pattern only seems to work if the derived class is itself templated. For instance, if we change the code to:
template<typename Derived>
struct traits;
template<typename Derived>
struct Base {
using size_type = typename traits<Derived>::size_type;
};
struct Derived1 : Base<Derived1>{
using size_type = size_t;
void print(){ std::cout << "Derived1" << std::endl; }
};
template <>
struct traits<Derived1> {
using size_type = size_t;
};
int main()
{
Derived1 d1;
d1.print();
}
then we get the error
prog.cc: In instantiation of 'struct Base<Derived1>':
prog.cc:21:19: required from here
prog.cc:18:58: error: invalid use of incomplete type 'struct traits<Derived1>'
using size_type = typename traits<Derived>::size_type;
^
prog.cc:14:8: note: declaration of 'struct traits<Derived1>'
struct traits;
^~~~~~
prog.cc: In function 'int main()':
prog.cc:33:9: error: 'Derived1' is not a template
Derived1<float> d1;
Could somebody give me an explanation indicating why the templated derived class compiles, but the untemplated class does not?
The issue you're seeing has nothing to do with CRTP.
Here's what the standard mentions.
If a class template has been declared, but not defined, at the point of instantiation (13.7.4.1),
the instantiation yields an incomplete class type (6.7). [Example:
template<class T> class X; X<char> ch; // error: incomplete type
X<char>
Your traits has only been declared at the point of instantiation of Base<Derived>, hence as per the standard(see above extraction from the standard), struct traits<Derived> yields an incomplete type.
You should reorder the code so that it sees the traits<Derived> specialization when Base<Derived> gets instantiated.
The compilation error you are seeing has nothing to do with CRTP, it's just a bit of a mish-mash of dependencies.
In the code without the templation, your "Base" struct needs the definition of the specialized "traits" struct but it only appears afterwards, so it tries to use the incomplete type it saw in the declaration above.
To get the code to work you need to have the "traits" specialization before the Base declaration, which requires you to also add a declaration of Derived 1, here is a compiling code:
class Derived1;
template<typename Derived>
struct traits;
template <>
struct traits<Derived1> {
using size_type = size_t;
};
template<typename Derived>
struct Base {
using size_type = typename traits<Derived>::size_type;
};
struct Derived1 : Base<Derived1>{
using size_type = size_t;
void print(){ std::cout << "Derived1" << std::endl; }
};
int main()
{
Derived1 d1;
d1.print();
}

How to make a particular constructor on a tempate type available only for a particular specialization in C++11?

I have a C++11 template that can be specialized with an arbitrary type parameter.
template<class ElementType>
class Foo
How do I declare a constructor that appears for the compiler's consideration only when ElementType is e.g. const uint8_t?
That is, I have a bunch of constructors that are generic over any ElementType, but I also want to have constructors that are only considered when ElementType is specialized in a particular way. (Allowing those constructors to be selected for other types would be unsafe.)
So far std::enable_if examples that I've found have been conditional on the types of the arguments of the constructors.
template<class ElementType>
struct Foo
{
template <typename T = ElementType>
Foo(typename std::enable_if<!std::is_same<T, const uint8_t>{}>::type* = nullptr) {}
template <typename T = ElementType>
Foo(typename std::enable_if<std::is_same<T, const uint8_t>{}>::type* = nullptr) {}
};
int main()
{
Foo<int> a{}; // ok, calls first constructor
Foo<const uint8_t> b{}; // ok, calls second constructor
}
wandbox example
You can break the class into two classes. The derived class' purpose is to be able to specialize constructors for different types. E.g.:
#include <cstdio>
#include <cstdint>
template<class ElementType>
struct Foo_
{
Foo_() { std::printf("%s\n", __PRETTY_FUNCTION__); }
};
template<class ElementType>
struct Foo : Foo_<ElementType>
{
using Foo_<ElementType>::Foo_; // Generic version.
};
template<>
struct Foo<uint8_t> : Foo_<uint8_t>
{
Foo() { std::printf("%s\n", __PRETTY_FUNCTION__); } // Specialization for uint8_t.
};
int main(int ac, char**) {
Foo<int8_t> a;
Foo<uint8_t> b;
}
The benefit of using the derived class here compared to enable_if is that:
The class can be partially specialized.
Only one specialization of the class is chosen for particular template parameters, rather than a set of constructors. When adding specializations for new types the existing enable_if expressions may need to be changed to make them more restrictive to avoid function overload set resolution ambiguity.

Compile error in calling a function with std::function argument

The minimal code below gives me a compile error:
#include <iostream>
#include <functional>
using namespace std;
template<typename ActionType, typename... Cols>
void print_action(function<ActionType*(Cols..., ActionType)> action_factory)
{
}
int main(int argc, char *argv[])
{
print_action<string, uint8_t>(function<string*(uint8_t, string)>());
return 0;
}
The error is:
foo.cc: In function ‘int main(int, char**)’:
foo.cc:13:69: error: no matching function for call to ‘print_action(std::function<std::basic_string<char>*(unsigned char, std::basic_string<char>)>)’
print_action<string, uint8_t>(function<string*(uint8_t, string)>());
^
foo.cc:13:69: note: candidate is:
foo.cc:7:6: note: template<class ActionType, class ... Cols> void print_action(std::function<ActionType*(Cols ..., ActionType)>)
void print_action(function<ActionType*(Cols..., ActionType)> action_factory)
^
foo.cc:7:6: note: template argument deduction/substitution failed:
foo.cc:13:69: note: mismatched types ‘std::basic_string<char>’ and ‘unsigned char’
print_action<string, uint8_t>(function<string*(uint8_t, string)>());
^
foo.cc:13:69: note: ‘std::function<std::basic_string<char>*(unsigned char, std::basic_string<char>)>’ is not derived from ‘std::function<std::basic_string<char>*(Cols ..., std::basic_string<char>)>’
I also try to change the input parameter to a simple pointer function by below code:
#include <iostream>
#include <functional>
using namespace std;
template<typename ActionType, typename... Cols>
void print_action(ActionType*(*action_factory)(Cols..., ActionType))
{
}
string* foo_factory(uint8_t cols, string act)
{
}
int main(int argc, char *argv[])
{
print_action<string, uint8_t>(foo_factory);
return 0;
}
It gives me the same error. After some works my last guess is that it is a bug of g++ because if I change the variadic template parameter to a simple parameter no errors happen.
Am I right or I missed some syntax of c++?
I use g++-4.8.4 with c++11 flag(I checked it using clang-3.4 and g++-4.9.2).
EDIT:
If I change the code to this:
#include <iostream>
#include <functional>
using namespace std;
template<typename ActionType, typename... Cols>
struct Foo
{
Foo()
{}
void print_action(function<ActionType*(Cols..., ActionType)> action_factory)
{
}
};
int main(int argc, char *argv[])
{
Foo<string, uint8_t> f;
f.print_action(function<string*(uint8_t, string)>());
return 0;
}
I get no error. I don`t understand this behavior because in both situations I defined the template parameters explicitly and I did not expect any deduction, but It seems that compiler does some deduction when it is a template function but not when it is a member function of a template class.
The issue is that you have (Cols..., ActionType). One might think that the compiler should notice that Cols... should be all the arguments before the end so long as the end is the same as ActionType, but this is not how the language works.
A simple solution would to just deduce the entire argument list. Compilation will fail anyway if you happen to use the final argument as in a way the type doesn't support, and you could always add in a static_assert to ensure that the final parameter is the same as ActionType if you really wanted.
template<typename ActionType, typename... Cols>
void print_action(function<ActionType*(Cols...)> action_factory)
{
//Maybe with a static_assert like this
using LastArg = typename std::tuple_element<
sizeof...(Cols)-1, //number of args - 1
std::tuple<Cols...>
>::type;
static_assert(std::is_same<LastArg, ActionType>::value,
"The final argument must be the same type as ActionType");
}
Live Demo
Usually variadic templates are written thus
template<typename First, typename... Rest> class test;
The compiler matches the first argument and leaves the rest (empty or more) to variadic part. The behaviour when reversed is not as expected. Variadic template arguments are greedy, in that, all arguments are eaten-up by it, leaving none to the last.
Your example code compiles fine, when the order is reversed:
template<typename ActionType, typename... Cols>
void print_action(function<ActionType*(ActionType, Cols...)>) {
}
int main()
{
print_action(function<string*(string, uint8_t)>());
}
Live example.
There's a difference between argument type deduction and instantiation. Quote from C++ Templates: The Complete Guide:
The process of replacing template parameters by concrete types is called instantiation. It results in an instance of a template.
When a function template is instantiated, we get a function out of it; same for class/struct.
It seems that compiler does some deduction when it is a template function but not when it is a member function of a template class.
There is no type deduction or instantiation happening for the function call. It is not a function template, but just a function. The call is just another ordinary function call.
However, the struct is really a struct template and a struct is created out of the template, when an object was created. For this struct template instantiation
template<typename ActionType, typename... Cols>
struct Foo;
the order is correct (the variadic argument is the last) and so it works.

c++11 template metaprogramming construct a std::unorderer_map at compile time

i trying to develop a Finite State Machine with template meta programming techniques, but i getting stuck with a map that it has to be fill at compile time, this the code(gcc 4.8 c++11):
#include <functional>
#include <type_traits>
#include <iostream>
#include <unordered_map>
namespace NSStateMachine {
//Definicion de estado unidad
template<class FSM, class From, class Event, class TO, bool(FSM::* transicion_fn)(const Event &)>
struct Transition
{
using FSM_TYPE=FSM;
using FROM_STATE= From;
using EVENT_TYPE= Event;
using TO_STATE_TYPE=TO;
using EVENT_BASE_TYPE = typename Event::BASE_TYPE;
static bool do_transition(FSM_TYPE& currenState, EVENT_BASE_TYPE const& aEvent)
{
return (currenState.*transicion_fn)(static_cast<EVENT_TYPE const&>(aEvent));
}
};
//States
template<class Transition, const Transition * const TransitionPtr, class ... Args>
class StateMachine
{
public:
StateMachine():transitionMap{{static_cast<typename Transition::TransitionID>(*TransitionPtr::TransitionID_Value),nullptr}}
{}
template<class Event>
bool evalEvent(const Event & aEvent)
{
std::cout<<"evento recibido"<<std::endl;
}
std::unordered_map<typename Transition::TransitionID, const Transition * const > transitionMap ;
};
}
int main()
{
//it doesnt compile, i canoot create the state machine
return 0;
}
The compile error:
error: 'TransitionPtr' is not a class, namespace, or enumeration
StateMachine():transitionMap{{static_cast<typename Transition::TransitionID>(*TransitionPtr::TransitionID_Value),nullptr}}
^
The problem seem to be in the line
transitionMap{{static_cast<typename Transition::TransitionID>(*TransitionPtr::TransitionID_Value),nullptr}}
i will try to init the unorderer_map with the automatic constructor.
i have defined this Transition::TransitionID as a class variable defined in the class represented by the template argument
I will really appreciate any help.
Thx!!!!
i have already test with default types , it compile and work this
The error message is pretty clear. TransitionPtr is a pointer, not a type, so you can't use it to the left of :: in TransitionPtr::TransitionID_Value.
Also, I don't think you'll find a way to initialize an unordered_set at compile time, since it doesn't have constexpr constructors and in general almost certainly uses heap allocations.

Specializing std::hash to derived classes

I have an abstract base class Hashable that classes that can be hashed derive from. I would now like to extend std::hash to all classes that derive from Hashable.
The following code is supposed to do exactly that.
#include <functional>
#include <type_traits>
#include <iostream>
class Hashable {
public:
virtual ~Hashable() {}
virtual std::size_t Hash() const =0;
};
class Derived : public Hashable {
public:
std::size_t Hash() const {
return 0;
}
};
// Specialization of std::hash to operate on Hashable or any class derived from
// Hashable.
namespace std {
template<class C>
struct hash {
typename std::enable_if<std::is_base_of<Hashable, C>::value, std::size_t>::type
operator()(const C& object) const {
return object.Hash();
}
};
}
int main(int, char**) {
std::hash<Derived> hasher;
Derived d;
std::cout << hasher(d) << std::endl;
return 0;
}
The above code works exactly as expected with gcc 4.8.1, but when I try to compile it with gcc 4.7.2, I get the following:
$ g++ -std=c++11 -o test test_hash.cpp
test_hash.cpp:22:8: error: redefinition of ‘struct std::hash<_Tp>’
In file included from /usr/include/c++/4.7/functional:59:0,
from test_hash.cpp:1:
/usr/include/c++/4.7/bits/functional_hash.h:58:12: error: previous definition of ‘struct std::hash<_Tp>’
/usr/include/c++/4.7/bits/functional_hash.h: In instantiation of ‘struct std::hash<Derived>’:
test_hash.cpp:31:24: required from here
/usr/include/c++/4.7/bits/functional_hash.h:60:7: error: static assertion failed: std::hash is not specialized for this type
Can anybody think of a way to make this specialization of std::hash work for any class derived from Hashable with gcc 4.7.2?
It seems like there is no proper way to do what I wanted to do. I have decided to just write separate specializations for each derived class, using the following macro:
// macro to conveniently define specialization for a class derived from Hashable
#define DEFINE_STD_HASH_SPECIALIZATION(hashable) \
namespace std { \
template<> \
struct hash<hashable> { \
std::size_t operator()(const hashable& object) const { \
return object.Hash(); \
} \
}; \
}
and then
// specialization of std::hash for Derived
DEFINE_STD_HASH_SPECIALIZATION(Derived);

Resources