I have custom List class like this:
template<class T>
struct iList{
constexpr bool empty() const{
return static_cast<const T *>(this)->size() == 0;
}
// several methods like empty(), some are non const.
};
// there are several classes like this one with different implementations
struct MyList : iList<MyList>{
constexpr unsigned size() const{
return 5;
}
};
int main(){
constexpr MyList list;
static_assert( ! list.empty() );
}
code is constexpr and simplified so I can use static_assert.
I want to get rid of CRTP pattern, because templates become way too ugly. However I do not want to use virtual functions.
One way I am thinking is following:
struct iList2{
protected:
template<class LIST>
constexpr static bool empty_(const LIST &list){
return list.size() == 0;
}
};
struct MyList2 : iList2{
constexpr unsigned size() const{
return 5;
}
constexpr bool empty() const{
return empty_(*this);
}
};
int main(){
constexpr MyList2 list2;
static_assert( ! list2.empty() );
}
In this case I need to call empty_ static member function in each list.
Another way is to use mixin, e.g. to inherit MyList and add empty() method. If I do this as templated class, I can even make typedef. However I do not like this approach as well.
Is there any possibility I am missing?
Related
I'm trying to get the multi_index_t code from the second answer here answered by davidhigh to work with C++11. C++11 does not support auto& type returns.
I converted the return types for the class, but I don't understand how/if it's possible to support the helper function multi_index() without using C++14.
The code:
#include<array>
template<int dim>
struct multi_index_t
{
std::array<int, dim> size_array;
template<typename ... Args>
multi_index_t(Args&& ... args) : size_array(std::forward<Args>(args) ...) {}
struct iterator
{
struct sentinel_t {};
std::array<int, dim> index_array = {};
std::array<int, dim> const& size_array;
bool _end = false;
iterator(std::array<int, dim> const& size_array) : size_array(size_array) {}
iterator& operator++()
{
for (int i = 0;i < dim;++i)
{
if (index_array[i] < size_array[i] - 1)
{
++index_array[i];
for (int j = 0;j < i;++j) { index_array[j] = 0; }
return *this;
}
}
_end = true;
return *this;
}
std::array<int, dim>& operator*() { return index_array; }
bool operator!=(sentinel_t) const { return !_end; }
};
iterator begin() const { return iterator{ size_array }; }
iterator end() const { return typename iterator::sentinel_t{}; }
};
template<typename ... index_t>
auto multi_index(index_t&& ... index) // <-- this doesn't compile
{
static constexpr int size = sizeof ... (index_t);
auto ar = std::array<int, size>{std::forward<index_t>(index) ...};
return multi_index_t<size>(ar);
}
According to this answer, you can't recursively expand the variadic function template via decltype(). Any ideas?
C++11 does not support auto& type returns.
So you can simply explicit the types.
For multi_index() you have that return a multi_index_t<size>, where size is sizeof...(index_t), so you can write
template<typename ... index_t>
multi_index_t<sizeof...(index_t)> multi_index(index_t&& ... index)
According to this answer, you can't recursively expand the variadic function template via decltype.
Correct, but I don't see recursion in your multi_index() function, so I don't see how apply recursion over decltype().
If you really want (but why?), you can explicit the returning type through decltype() as follows
template<typename ... index_t>
auto multi_index(index_t&& ... index)
-> decltype( multi_index_t<sizeof...(index_t)>
{ std::array<int, sizeof...(index_t)>
{{ std::forward<index_t>(index) ... }} } )
but I don't see a reason to do this instead of simply explicit multi_index_t<sizeof...(index_t)>
I am unable to specialize the template member function below. I have looked at the solution given to answer similar question on SOF but the solution that is proposed is same as the code I have below but it does not seem to work. I am missing something for sure.
enum EStep
{
eStep1, eStep2, eStep3
};
template<int16_t iDevice>
struct Device
{
template<EStep step>
static constexpr bool isType() { return false; }
};
template<> template<>
constexpr bool Device<int16_t>::isType<eStep1>()
{
return true;
}
template<> template<>
constexpr bool Device<int16_t>::isType<eStep1>()
{
return true;
}
Device is a template of int16_t, so to specialize it, you'd need to provide an int16_t value as the template argument. e.g.
template<> template<>
constexpr bool Device<999>::isType<eStep1>()
Consider the following code:
#include <boost/iterator/iterator_facade.hpp>
#include <map>
// Class implements an stl compliant iterator to access the "sections" stored within a configuration.
template < typename _Iterator, typename _Reference >
class Section
: public boost::iterator_facade<
Section< _Iterator, _Reference >,
_Iterator,
boost::random_access_traversal_tag,
_Reference
>
{
private:
// Define the type of the base class:
typedef boost::iterator_facade<
Section< _Iterator, _Reference >,
_Iterator,
boost::random_access_traversal_tag,
_Reference
> base_type;
public:
// The following type definitions are common public typedefs:
typedef Section< _Iterator, _Reference > this_type;
typedef typename base_type::difference_type difference_type;
typedef typename base_type::reference reference;
typedef _Iterator iterator_type;
public:
explicit Section( const iterator_type it )
: m_it( it )
{ }
// Copy constructor required to construct a const_iterator from an iterator:
template < typename _U >
Section( const Section< _U, _Reference > it )
: m_it( it.m_it )
{ }
private:
// The following classes are friend of this class to ensure access onto the private member:
friend class boost::iterator_core_access;
template < typename _Iterator, typename _Reference > friend class Section;
void increment( ){ ++m_it; } // Advance by one position.
void decrement( ){ --m_it; } // Retreat by one position.
void advance( const difference_type& n ){ m_it += n }; // Advance by n positions.
bool equal( const this_type& rhs ) const{ return m_it == rhs.m_it; } // Compare for equality with rhs.
reference dereference( ) const { return m_it->second; } // Access the value referred to.
difference_type distance_to( const this_type& rhs ) const{ return rhs.m_it - m_it; } // Measure the distance to rhs.
private:
// Current "section" iterator:
iterator_type m_it;
};
struct Data
{
void f( ) const
{ }
};
typedef std::map< int, Data > map_type;
typedef Section< const map_type::const_iterator, const Data& > iterator_type;
map_type g_map;
iterator_type begin( )
{
return iterator_type( g_map.begin( ) );
}
void main( )
{
iterator_type i = begin( );
// i->f( ); // <--- error C2039: 'f' : is not a member of 'std::_Tree_const_iterator<_Mytree>'
( *i ).f( );
}
So the iterator facade shall return a reference to Data type. This works well when dereference operator is called but compile fails when operator->() is called. So I am a bit confused because operator->() tries to return a std::map::iterator. Any ideas ?
The iterator returns an iterator on dereference. To get the f part, you need to dereference twice.
It looks a lot like you misunderstood the meaning of the template arguments to iterator_facade. The second argument is not supposed to be any iterator type (this is what causes all your trouble). Instead you should use it to name your value_type.¹
From the way you specified the dereference operation (and Ref) and wanted to use it in main (i->f()) it looks like you just wanted to iterate the map's values. So, I'd rewrite the whole thing using more descriptive names as well, and here it is, working:
Live On Coliru
#include <boost/iterator/iterator_facade.hpp>
#include <map>
// Class implements an stl compliant iterator to access the "sections" stored within a configuration.
template <typename Map, typename Value = typename Map::mapped_type>
class MapValueIterator : public boost::iterator_facade<MapValueIterator<Map>, Value, boost::random_access_traversal_tag, Value const&> {
private:
// Define the type of the base class:
typedef Value const& Ref;
typedef boost::iterator_facade<MapValueIterator<Map>, Value, boost::random_access_traversal_tag, Ref> base_type;
public:
// The following type definitions are common public typedefs:
typedef MapValueIterator<Map> this_type;
typedef typename base_type::difference_type difference_type;
typedef typename base_type::reference reference;
typedef typename Map::const_iterator iterator_type;
public:
explicit MapValueIterator(const iterator_type it) : m_it(it) {}
// Copy constructor required to construct a const_iterator from an iterator:
template <typename U, typename V> MapValueIterator(const MapValueIterator<U,V> it) : m_it(it.m_it) {}
private:
// The following classes are friend of this class to ensure access onto the private member:
friend class boost::iterator_core_access;
template <typename U, typename V> friend class MapValueIterator;
void increment() { std::advance(m_it); } // Advance by one position.
void decrement() { std::advance(m_it, -1); } // Retreat by one position.
void advance(const difference_type &n) { std::advance(m_it, n); } // Advance by n positions.
bool equal(const this_type &rhs) const { return m_it == rhs.m_it; } // Compare for equality with rhs.
reference dereference() const { return m_it->second; } // Access the value referred to.
difference_type distance_to(const this_type &rhs) const { return rhs.m_it - m_it; } // Measure the distance to rhs.
private:
// Current iterator:
iterator_type m_it;
};
#include <iostream>
struct Data {
void f() const {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
};
typedef std::map<int, Data> map_type;
template <typename Map>
MapValueIterator<Map> map_value_iterator(Map const& m) {
return MapValueIterator<Map>(m.begin());
}
int main() {
map_type g_map;
auto i = map_value_iterator(g_map);
i->f();
}
Which prints the output
void Data::f() const
as you'd expect.
Note that there are numerous places where I implemented the member functions using standard library facilities. Note as well, the iterator "mimics" random access, but it won't have the expected performance characteristics (increment is O(n)).
Final note: I'd recommend against having the implicit conversion constructor. I think you can do without it.
¹ The reference-type should typically be the same (but ref-qualified) except in rare cases where you actually "proxy" the values. This is an advanced topic and rarely should be used.
the following code produces an internal compiler error (VS2015)
struct A
{
constexpr A(){}
constexpr int bar()
{
return 3;
}
};
struct B : A
{
constexpr B(){}
constexpr int foo()
{
return A::bar();
}
};
int main()
{
constexpr B b;
constexpr int dummy = b.foo();
return 1;
}
However, if i'd remove the A:: qualifier:
constexpr int foo()
{
return bar();
}
it will be compiled.
problem arises when these methods have the same name, and I need to invoke the base class method. (e.g. when using recursive template inheritence)
any workarounds?
The actual problem is b is declared as const (constexpr implies const on objects) and you are trying to call non-const (since C++14, constexpr doesn't imply const on methods, see here) method with the const object...
According to the standard, you should not be able to solve the problem by simply removing A:: nor by the static_cast the way you did. Pre-RTM version of Visual Studio 2015 allows you to do this only because its support for constexpr is preliminary and very buggy. C++11 constexpr (but unfortunately not C++14 extended constexpr) expected to be fully supported in the RTM version of VS 2015 (see here).
The correct version of your code is:
struct A
{
constexpr A(){}
constexpr int bar() const
{
return 3;
}
};
struct B : A
{
constexpr B(){}
constexpr int foo() const
{
return A::bar();
}
};
int main()
{
constexpr B b;
constexpr int dummy = b.foo();
return 1;
}
Found a solution.
"this" should be casted to const A*:
struct B : A
{
constexpr B(){}
constexpr int foo()
{
return static_cast<const A*>(this)->bar();
}
};
Also works when the methods have the same name.
Using variadic template arguments together with a simple template argument I have experienced some strange behaviour of is_base_of when it was instantiated from a binded functor.
Here is the code:
template <class T, class Index>
class Base{};
template<typename T>
struct Checker {
typedef int result_type;
// Returns 1 if a given T type is descendant of Base<T,First>
template<typename First, typename ...Args>
result_type operator()(First&& first, Args&&... params)
{
return check(std::is_base_of<Base<T,First>, T>(),
std::forward<First>(first),
std::forward<Args>(params)...);
}
template<typename ...Args>
result_type check(const std::true_type&, Args&&... params)
{
return 1;
}
template<typename ...Args>
result_type check(const std::false_type&, Args&&... params)
{
return 0;
}
};
struct A {};
struct B : Base<B,int> {};
int main()
{
Checker<A> ch1;
std::cout<<ch1(3.14)<<std::endl;
Checker<B> ch2;
std::cout<<ch2(1 ,3.14)<<std::endl; // output is 1
std::cout<<std::bind(ch2, 1, 3.14)()<<std::endl; // output is 0 but it should be 1 !
return 0;
}
The program output is:
0
1
0
But I would expect:
0
1
1
Am I using the variadic templates in a wrong way? Is there any other (correct) way to get the first type of a variadic type list like Args? Why this is a problem only when it is used with the bind expression?
Note, if I am modifing the Base template to have only one template parameter, then the bind expression works:
template <class T>
class Base{};
template<typename T>
struct Checker {
typedef int result_type;
// Returns 1 if a given T type is descendant of Base<T>
template<typename ...Args>
result_type operator()(Args&&... params)
{
return check(std::is_base_of<Base<T>, T>(),
std::forward<Args>(params)...);
}
template<typename ...Args>
result_type check(const std::true_type&, Args&&... params)
{
return 1;
}
template<typename ...Args>
result_type check(const std::false_type&, Args&&... params)
{
return 0;
}
};
struct A {};
struct B : Base<B> {};
int main()
{
Checker<A> ch1;
std::cout<<ch1(3.14)<<std::endl;
Checker<B> ch2;
std::cout<<ch2(3.14)<<std::endl; // output is 1
std::cout<<std::bind(ch2, 3.14)()<<std::endl; // output is 1 this time!
return 0;
}
You're not getting the expected output because the data-type of First in your Checker function object when called after std::bind() is of type int&, not int.
Therefore std::is_base_of<Base<B,int&>, B> does not instantiate to a std::true_type for the call to Checker::check.
The problem is that std::bind is creating an object that internally stores the arguments for the function you are passing to it. Therefore there is a named l-value as a non-static data-member of the object returned by std::bind that is holding the value you passed as an argument to be bound to your function. When that non-static data-member is then passed to the r-value reference at the time you call the operator() of the functor, it's passed as an l-value reference, since it is no longer a temporary object. You would have a similar problem if you did something like:
int x = 1;
Checker<B> ch2;
std::cout<<ch2(x, 3.14)<<std::endl;
The named-value x is an l-value, and would be passed to the first argument in your operator() method as an l-value reference, not as temporary, since first is a r-value reference. Therefore your type would end up again as an int& and not an int, and you'd print a value of 0.
To fix this problem, you can do something like:
template<typename First, typename ...Args>
result_type operator()(First&& first, Args&&... params)
{
if (std::is_reference<First>::value)
{
return check(std::is_base_of<Base<T, typename std::remove_reference<First>::type>, T>(),
std::forward<First>(first),
std::forward<Args>(params)...);
}
else
{
return check(std::is_base_of<Base<T,First>, T>(),
std::forward<First>(first),
std::forward<Args>(params)...);
}
}
This will strip off the reference-type of the object and give you the results you want.
Unfortunately std::is_reference did not give me the expected result on a more complicated issue.
So finally I choosed providing the reference and const-reference overloads:
template<typename First, typename ...Args>
result_type operator()(First& first, Args&&... params)
{
return check(std::is_base_of<Base<T,First>, T>(),
first,
std::forward<Args>(params)...);
}
template<typename First, typename ...Args>
result_type operator()(const First& first, Args&&... params)
{
return check(std::is_base_of<Base<T,First>, T>(),
first,
std::forward<Args>(params)...);
}