Related
I am currently using C++14.
I would like to define a Matrix class which I can use for defining runtime matrices, but also constexpr matrices. I also would like to define static constexpr matrices based on such a class.
I consider this as a starting point for the Matrix class.
Then I would like to write something as:
static constexpr Matrix<double,2,2> staticmat{0.1,0.2,0.3,0.4};
so that staticmat is constexpr and unique, being static.
However, in order to initialise this, I would need a constexpr array or a constexpr initialiser list (not implemented in the link I posted, but not much would change). So I could write something like:
static constexpr std::array<double,4> staticmattmp{0.1,0.2,0.3,0.4};
static constexpr Matrix<double,2,2> staticmat(staticmattmp);
This would be ugly because I have to define two things just for one, but, if it worked, I could accept it. Unfortunately the compiler says unknown type name 'staticmattmp'.
How can I solve this, maybe in an elegant way?
How can I solve this, maybe in an elegant way?
I don't know if it's elegant but... with a little work...
First of all, define the following using
template <typename T, std::size_t>
using getType = T;
Next re-declare (declare only; not define) Matrix as follows
template <typename, std::size_t NR, std::size_t NC,
typename = std::make_index_sequence<NR*NC>>
class Matrix;
Now declare your Matrix as a class partial specialization adding a constructor that receive NR*NC elements of type T and use them to initialize the internal std::array
template <typename T, std::size_t NR, std::size_t NC, std::size_t ... Is>
class Matrix<T, NR, NC, std::index_sequence<Is...>>
{
public:
using value_type = T;
constexpr Matrix (getType<value_type, Is> ... vals)
: values_{{vals...}}
{}
// other member and methods
};
But don't forget to declare as default the destructor (maybe also constructor and operator=()).
The following is a full compiling C++14 example
#include <array>
#include <type_traits>
template <typename T, std::size_t>
using getType = T;
template <typename, std::size_t NR, std::size_t NC,
typename = std::make_index_sequence<NR*NC>>
class Matrix;
template <typename T, std::size_t NR, std::size_t NC, std::size_t ... Is>
class Matrix<T, NR, NC, std::index_sequence<Is...>>
{
public:
using value_type = T;
constexpr Matrix (getType<value_type, Is> ... vals)
: values_{{vals...}}
{}
constexpr Matrix (std::array<T, NR*NC> const & a)
: values_{a}
{}
constexpr Matrix (std::array<T, NR*NC> && a)
: values_{std::move(a)}
{}
constexpr Matrix () = default;
~Matrix() = default;
constexpr Matrix (Matrix const &) = default;
constexpr Matrix (Matrix &&) = default;
constexpr Matrix & operator= (Matrix const &) = default;
constexpr Matrix & operator= (Matrix &&) = default;
constexpr T const & operator() (std::size_t r, std::size_t c) const
{ return values_[r*NC+c]; }
T & operator() (std::size_t r, std::size_t c)
{ return values_[r*NC+c]; }
constexpr std::size_t rows () const
{ return NR; }
constexpr std::size_t columns () const
{ return NC; }
private:
std::array<T, NR*NC> values_{};
};
int main()
{
static constexpr Matrix<double,2,2> staticmat{0.1,0.2,0.3,0.4};
}
I need to set up a large number of std::vector in a lookup library. The all have the structure:
{N, N, ..., -N, -N}
I can do that with a number of templated functions:
template<int N>
static constexpr std::initializer_list<int> H2 = {N, -N};
template<int N>
static constexpr std::initializer_list<int> H4 = {N, N, -N -N};
...
from which I can simply do:
std::vector<int> v22 = H2<3>
std::vector<int> v35 = H3<5>
etc.
But would there be a way to include also the numbers 2, 4 etc. as a template parameter?
Yes, it is possible by using std::integer_sequence and variable template specialization:
template <typename, int N>
static constexpr std::initializer_list<int> HImpl;
template <int N, int... Is>
static constexpr std::initializer_list<int> HImpl<std::index_sequence<Is...>, N>
= {(Is < sizeof...(Is) / 2) ? N : -N...};
template <int Count, int N>
static constexpr auto H = HImpl<std::make_index_sequence<Count>, N>;
Usage:
int main()
{
std::vector<int> v = H<10, 1>;
for(int x : v) std::cout << x << ' ';
}
Output:
1 1 1 1 1 -1 -1 -1 -1 -1
live example on wandbox.org
I wonder why this choice is made. It would allow to write many functions in a very clear and neat way.. for instance:
int greatestCommonDivisor(int a, int b)
{
if (b > a)
std::tie(a, b) = { b, a };
while (b > 0)
std::tie(a, b) = { b, a % b };
return a;
}
std::initializer_list is a homogeneous collection of items, while std::tuple is heterogeneous. The only case where it makes sense to define a std::tuple::operator= for std::initializer_list is when the tuple is homogeneous and has the same size as the initializer list, which is a rare occurrence.
(Additional information in this question.)
Solution/workaround: you can use std::make_tuple instead:
int greatestCommonDivisor(int a, int b)
{
if (b > a)
std::tie(a, b) = std::make_tuple(b, a);
while (b > 0)
std::tie(a, b) = std::make_tuple(b, a % b);
return a;
}
...or std::tuple's constructor in C++17 (thanks to Template argument deduction for class templates):
int greatestCommonDivisor(int a, int b)
{
if (b > a)
std::tie(a, b) = std::tuple{b, a};
while (b > 0)
std::tie(a, b) = std::tuple{b, a % b};
return a;
}
Why does
std::tie(a,b) = {b, a};
not compile?
{} on the right hand side of an assignment can only call a non-explicit constructor of an argument of operator=.
The operator= overloads available are:
tuple& operator=( const tuple& other );
tuple& operator=( tuple&& other );
template< class... UTypes >
tuple& operator=( const tuple<UTypes...>& other );
template< class... UTypes >
tuple& operator=( tuple<UTypes...>&& other );
template< class U1, class U2 >
tuple& operator=( const pair<U1,U2>& p );
template< class U1, class U2 >
tuple& operator=( pair<U1,U2>&& p );
The template operator overloads cannot deduce their types from {} (note: this may change in C++17), leaving:
tuple& operator=( const tuple& other );
tuple& operator=( tuple&& other );
where tuple is std::tuple<int&, int&> in this case.
The tuple constructor for tuple<Ts...> that perfect forwards element-wise construction is explicit (#3 on that list). {} will not call an explicit constructor.
The conditionally non-explicit constructor takes Ts const&...; it does not exist if the Ts are non-copyable, and int& is non-copyable.
So there are no viable types to construct from {int&, int&}, and overload resolution fails.
Why does the standard not fix this? Well, we can do it ourselves!
In order to fix this, we'd have to add a special (Ts...) non-explicit constructor to tuple that only exists if the Ts types are all references.
If we write a toy tuple:
struct toy {
std::tuple<int&, int&> data;
toy( int& a, int& b ):data(a,b) {} // note, non-explicit!
};
toy toy_tie( int& a, int& b ) { return {a,b}; }
and use it, you'll notice that
std::tie(a, b) = {b, a};
compiles and runs.
However,
std::tie(a, b) = { b, a % b };
does not, as a%b cannot be bound to int&.
We can then augment toy with:
template<class...>
toy& operator=( std::tuple<int, int> o ) {
data = o;
return *this;
}
(+ defaulted special member functions. template<class...> ensures it has lower priority than the special member functions, as it should).
This which lets assign-from {int,int}. We then run it and... get the wrong result. The gcd of 5,20 is 20. What went wrong?
toy_tie(a, b) = std::tie( b, a );
with both a and b bound to references is not safe code, and that is what
toy_tie(a, b) = { b, a };
does.
In short, doing this right is tricky. In this case, you need to take a copy of the right hand side before assigning to be safe. Knowing when to take a copy and when not to is also tricky.
Having this work implicitly looks error prone. So it is, in a sense, accidental that it doesn't work, but fixing it (while possible) looks like a bad idea.
live example.
in here http://en.cppreference.com/w/cpp/utility/tuple/tuple_element given possible implementation of std::tuple_element.
template< std::size_t I, class T >
struct tuple_element;
// recursive case
template< std::size_t I, class Head, class... Tail >
struct tuple_element<I, std::tuple<Head, Tail...>>
: std::tuple_element<I-1, std::tuple<Tail...>> { };
// base case
template< class Head, class... Tail >
struct tuple_element<0, std::tuple<Head, Tail...>> {
typedef Head type;
};
But, this implementation need deep recursion instantiation, if tuple has a lot parameters ( more that 100 or 200 parameters).
Q1: Why C++11 was not added special operator for getting elements by index?
like tuple[2] or tuple[0] ?
Q2: Is possible reduce the deep instantiation? For example in D language more template algorithms (in typetuple) needed O(log(N) ) deep instantiation.
EDIT: Q1: Why C++11 was not added special operator for getting elements by index from variadic templates?
like template< class ...T> struct index{ typedef T[3] third_element;}
I think this implementation has O(log(N)) instantiation depth; kudos to Xeo for the O(log(N)) indices trick (modified to use std::size_t instead of unsigned).
Edit: I realized there's a different, simpler and probably faster (compilation time) solution to get the nth type of a tuple.
// from https://stackoverflow.com/a/13073076
// indices trick in O(log(N)) instantiations, by Xeo
// using aliases for cleaner syntax
template<class T> using Invoke = typename T::type;
template<std::size_t...> struct seq{ using type = seq; };
template<class S1, class S2> struct concat;
template<std::size_t... I1, std::size_t... I2>
struct concat<seq<I1...>, seq<I2...>>
: seq<I1..., (sizeof...(I1)+I2)...>{};
template<class S1, class S2>
using Concat = Invoke<concat<S1, S2>>;
template<std::size_t N> struct gen_seq;
template<std::size_t N> using GenSeq = Invoke<gen_seq<N>>;
template<std::size_t N>
struct gen_seq : Concat<GenSeq<N/2>, GenSeq<N - N/2>>{};
template<> struct gen_seq<0> : seq<>{};
template<> struct gen_seq<1> : seq<0>{};
Implementation of / similar to std::tuple_element:
namespace detail
{
template<std::size_t>
struct Any
{
Any(...) {}
};
template<typename T>
struct wrapper { using type = T; };
template<std::size_t... Is>
struct get_nth_helper
{
template<typename T>
static auto deduce(Any<Is>..., wrapper<T>, ...) -> wrapper<T>;
};
template<std::size_t... Is, typename... Ts>
auto deduce_seq(seq<Is...>, wrapper<Ts>... pp)
-> decltype( get_nth_helper<Is...>::deduce(pp...) );
}
#include <tuple>
template<std::size_t n, class Tuple>
struct tuple_element;
template<std::size_t n, class... Ts>
struct tuple_element<n, std::tuple<Ts...>>
{
using wrapped_type = decltype( detail::deduce_seq(gen_seq<n>{},
detail::wrapper<Ts>()...) );
using type = typename wrapped_type::type;
};
Usage example:
#include <typeinfo>
#include <iostream>
int main()
{
std::tuple<int, double, bool, char> t;
tuple_element<1, decltype(t)>::type x;
std::cout << typeid(x).name() << std::endl;
}
Thanks to #Barry for pointing out an issue in an earlier version of this answer with function/array types, and providing a fix.
Original version:
(Note: This version is simplified and doesn't add cv-qualifiers.)
#include <tuple>
namespace detail
{
template < std::size_t Index, class Arg >
struct s_get_one
{
// declare a function that links an Index with an Arg type
friend Arg get(s_get_one, std::integral_constant<std::size_t, Index>);
};
template < typename... Bases >
struct s_get : Bases... {};
}
template < std::size_t I, class T >
struct tuple_element;
template < std::size_t I, class... Args >
struct tuple_element < I, std::tuple<Args...> >
{
template<class T>
struct wrapper { using type = T; };
// deduce indices from seq helper
template < std::size_t... Is >
static auto helper(seq<Is...>)
-> detail::s_get< detail::s_get_one<Is, wrapper<Args>>... >;
// generate indices in O(log(N)) and use name lookup to find the type
using IC = std::integral_constant<std::size_t, I>;
using wrapped_type = decltype( get(helper(gen_seq<sizeof...(Args)>{}), IC{}) );
using type = typename wrapped_type::type;
};
Why C++11 was not added special operator for getting elements by index? like tuple2 or tuple[0] ?
First, because even if they did, it'd still work the same way: with recursion. Tuples are primarily a library feature. Though they piggy-back off of language features like variadic templates, they were more or less functional in C++98/03.
Second, that would not be possible. Not without a very difficult language change.
It's not clear what you mean by tuple[2].
If you mean that std::tuple<int, float, std::string>[2] should somehow resolve to the typename std::string, then that means you now need to explain why this works. Again, tuples are a library feature, not a language construct. So there would have to be some language construct whereby typename[integer] is a valid construct. What would that be and what would it mean?
If you mean that given:
std::tuple<int, float, std::string> tpl{...};
We should be able to get the string with tpl[2], that's several shades of "not going to happen". C++ is a statically typed language. The only reason std::get is able to get away with what it does is that the integer index is not a function parameter; it is a template parameter. That is what allows std::get<0> to return a completely different type from std::get<2>. That can't happen with operator[](int); that function must always return the same type.
So now you'd need to have something like template<class T, int i> ... operator[](). And that would be very confusing, because you can no longer do tpl[runtimeValue] on that type (since template parameters must be compile-time values). There is no such type where operator[] is restricted from being able to work on runtime values. So you'd be creating a very oddball type.
And even then... it would still have to do recursion to get the value.
Is possible reduce the deep instantiation?
Outside of compile times (which is not an unreasonable issue), what does it matter? A decent inliner will throw most of them away.
As for compile times, there are non-recursive implementations of various features of std::tuple. Whether they can do tuple_element non-recursively, I don't think so. This libc++ implementation seems to suggest that it can't, despite implementing the tuple itself non-recursively.
template< int ...i> struct seq{};
// GCC couldn't optimize sizeof..(i) ,
//see http://stackoverflow.com/questions/19783205/why-sizeof-t-so-slow-implement-c14-make-index-sequence-without-sizeof
//so I use direct variable `s` instead of it.
// i.e. s == number of variadic arguments in `I`.
template< int s, typename I, typename J > struct concate;
template< int s, int ...i, int ...j>
struct concate<s, seq<i...>, seq<j...> >
{
typedef seq<i..., (s + j)...> type;
};
template<int n> struct make_seq_impl;
template< int n> using make_seq = typename make_seq_impl<n>::type;
template<> struct make_seq_impl<0>{ typedef seq<> type;};
template<> struct make_seq_impl<1>{ typedef seq<0> type;};
template<int n> struct make_seq_impl: concate< n/2, make_seq<n/2>, make_seq<n-n/2>>{};
template< typename ...T> using seq_for = make_seq< sizeof...(T) > ;
//----------------------------------
template< int i, typename T> struct id{};
template< typename T> struct id<0,T>{ typedef T type;};
template< typename ...T> struct base : T ... {};
template< typename ...T> struct tuple{};
template< std::size_t i, typename Tuple> struct tuple_element;
template< std::size_t i, typename ...T>
struct tuple_element< i, tuple<T...> >
{
template< typename Seq > struct apply;
template< int ...j > struct apply< seq<j...> >
{
// j xor i ==> ( 0 xor i), (1 xor i), (2 xor i ),...(i xor i) ...
// => i0, i1, ..., 0 (at pos i) ...
// and only id<0,T> has `type`.
typedef base< id< (j xor i), T> ... > base_t;
typedef typename base_t::type type;
};
typedef typename apply< seq_for<T...> >::type type;
};
I noticed, that in [24.4.7] of the last C++-Std Doc N3291 max ist not constexpr:
template<class T> const T& max(const T& a, const T& b);
Therefore, it is not allowed to use it in a static_assert for example. Correct?
static_assert( max(sizeof(int),sizeof(float)) > 4, "bummer" );
That is correct.
I imagine the reason is simply that std::max calls T::operator< for an arbitrary type T and for std::max to be constexpr, it would require T::operator< to be constexpr, which is unknown.
This is correct; std::min and std::max are not constexpr, not even in the latest draft of C++14 (N3690), so they cannot be used within constant expressions.
There is no good reason for this, only bad reasons. The most significant bad reason is that the C++ committee is composed of individuals who have a limited amount of time to work on standardization, and no-one has put in the work required to make these functions constexpr yet.
Note N3039, a change to the C++ standard adopted in 2010, that slightly extended the constexpr facility specifically so that function such as min and max could be made constexpr.
You can work around this by defining your own min and max functions:
template<typename T>
constexpr const T &c_min(const T &a, const T &b) {
return b < a ? b : a;
}
template<typename T, class Compare>
constexpr const T &c_min(const T &a, const T &b, Compare comp) {
return comp(b, a) ? b : a;
}
template<typename T>
constexpr const T &c_min_impl(const T *a, const T *b) {
return a + 1 == b ? *a : c_min(*a, c_min_impl(a + 1, b));
}
template<typename T>
constexpr T c_min(std::initializer_list<T> t) {
return c_min_impl(t.begin(), t.end());
}
// ... and so on
this works on c++ 11
template<const Sz a,const Sz b> constexpr Sz staticMax() {return a>b?a:b;}
use:
staticMax<a,b>()
and of course a and b must be constexpr