modification of ‘<temporary>’ is not a constant expression - c++

This code used to compile with earlier g++ versions, e.g. 5.3.
Using 10.2 I'm getting the following (using compiler option -std=c++11)
tmp1.cpp: In function ΓÇÿint main(int, char**)ΓÇÖ:
tmp1.cpp:17:117: error: modification of ΓÇÿ<temporary>ΓÇÖ is not a constant expression
17 | static constexpr std::initializer_list<std::pair<int, std::initializer_list<int> > > s={{0, {1}}, {1, {2}}, {2, {3}}};
| ^
tmp1.cpp:18:33: error: non-constant condition for static assertion
18 | static_assert(isSortedPairVector(s.begin(), s.end()), "sorted");
| ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~
I think this has something to do with an initializer_list containing another initializer_list -- as with
std::initializer_list<std::pair<int, int> >
everything is fine.
Here is the code:
#include <initializer_list>
#include <utility>
#include <iostream>
template<typename T>
constexpr bool isSortedPairVector(const T&_p, const T&_pEnd)
{ return _p == _pEnd || _p + 1 == _pEnd
? true
: _p->first < (_p + 1)->first
&& isSortedPairVector(_p + 1, _pEnd);
}
int main(int, char**)
{
static constexpr std::initializer_list<std::pair<int, std::initializer_list<int> > > s={{0, {1}}, {1, {2}}, {2, {3}}};
static_assert(isSortedPairVector(s.begin(), s.end()), "sorted");
}
Curiously -- making the contained initializer_list empty makes the code compileable. e.g.
static constexpr std::initializer_list<std::pair<int, std::initializer_list<int> > > s={{0, {}}, {1, {}}, {2, {}}};

The solution to this problem is to make every std::initializer_list object used inside another std::initializer_list a constexpr variable.
Thus the following compiles:
static constexpr std::initializer_list<int> s1({1, 2});
static constexpr std::initializer_list<
std::pair<int, std::initializer_list<int> >
> s={
{0, s1},
{1, s1},
{2, s1}
};

Related

What happened when I pass a nested braced-init-lists to constructor in C++?

I passed an nested braced-init-lists to class constructor:
#include <iostream>
#include <type_traits>
#include <variant>
#include <vector>
class NestedInteger final {
public:
NestedInteger(int i) : type_(INT), val_int_(i) {}
// NestedInteger(std::initializer_list<NestedInteger> ni) {
template <typename T>
NestedInteger(std::initializer_list<T> ni) {
for (auto it = ni.begin(); it != ni.end(); it++) {
val_vec_.push_back(*it);
}
}
private:
enum { INT, VECTOR } type_;
int val_int_;
std::vector<NestedInteger> val_vec_;
};
int main() {
NestedInteger ni1{1};
NestedInteger ni2{1, 2, 3};
NestedInteger ni3{{1}, 2, 3};
NestedInteger ni4{{1, 2, 3}};
NestedInteger ni5{{1, 2, 3}, {4, 5, 6, 7}};
return 0;
}
And I got compilation error:
t.cpp:29:44: error: no matching function for call to ‘NestedInteger::NestedInteger(<brace-enclosed initializer list>)’
29 | NestedInteger ni5{{1, 2, 3}, {4, 5, 6, 7}};
| ^
t.cpp:12:3: note: candidate: ‘template<class T> NestedInteger::NestedInteger(std::initializer_list<_Tp>)’
12 | NestedInteger(std::initializer_list<T> ni) {
| ^~~~~~~~~~~~~
t.cpp:12:3: note: template argument deduction/substitution failed:
t.cpp:29:44: note: candidate expects 1 argument, 2 provided
29 | NestedInteger ni5{{1, 2, 3}, {4, 5, 6, 7}};
...
I read the list initialization in cppreference here. And I can tell the expression belongs to the first syntax type:
T object { arg1, arg2, ... }; (1)
initialization of a named variable with a braced-init-list (that is, a possibly empty brace-enclosed list of expressions or nested braced-init-lists)
I can't understand the explanation about the effects.
Could you help to figure out:
Which item in the explanation does this case match?
Is this a non-deduced contexts described here?
By the way, if I change the template to specific type as the commented line, the compilation error disapeared.

Why can't I use a std::tuple in a constexpr lambda function

I have the following code:
#include <string_view>
#include <array>
#include <tuple>
struct Variable
{
size_t index;
std::string_view name;
std::tuple<float, float> bounds;
};
constexpr std::array<Variable, 3> myarray = [](){
std::array<Variable, 3> res{};
std::array<std::string_view, 3> strings = {"myvar1", "myvar2", "myvar3"};
std::array<std::tuple<float, float>, 3> bounds = {{{0,1}, {1,2}, {2,3}}};
for (std::size_t i = 0; i != res.size(); ++i) {
res[i] = {i, strings[i], bounds[i]};
}
return res;
}();
but this code does not compile due to the std::tuple. What is the reason I can't use std::tuple inside a lambda function?
I'm using
c++ -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -g -o main.o -c main.cpp
to compile the code.
Version of the compiler is: gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)
The error I get is:
../main.cpp:53:3: error: call to non-constexpr function ‘<lambda()>’
}();
^
../main.cpp:44:51: note: ‘<lambda()>’ is not usable as a constexpr function because:
constexpr std::array<Variable, num_vars> xrt = [](){
^
../main.cpp:51:39: error: call to non-constexpr function ‘Variable& Variable::operator=(Variable&&)’
res[i] = {i, strings[i], bounds[i]};
^
../main.cpp:16:8: note: ‘Variable& Variable::operator=(Variable&&)’ is not usable as a constexpr function because:
struct Variable
^~~~~~~~
Neither tuple nor pair have constexpr assignment in C++17.
But even a trivial struct containing pair of values would do the job. You may want to implement own constexpr-compatible structure if required. Trivial version without fluff you need:
struct Couple {
float a, b;
};
struct Variable
{
size_t index;
std::string_view name;
Couple bounds;
};
constexpr std::array<Variable, 3> myarray = [](){
std::array<Variable, 3> res{};
std::array<std::string_view, 3> strings = {"myvar1", "myvar2", "myvar3"};
std::array<Couple, 3> bounds = {{{0,1}, {1,2}, {2,3}}};
for (std::size_t i = 0; i != res.size(); ++i) {
res[i] = {i, strings[i], bounds[i]};
}
return res;
}();
It's possible to arrangle code the way it would use tuple for future standard
std::tuple's assignment operators are not constexpr until c++20. If you avoid assignment operators and construct your tuples in-place then your code compiles:
constexpr std::array<Variable, 3> myarray = [](){
std::array<std::string_view, 3> strings = {"myvar1", "myvar2", "myvar3"};
std::array<std::tuple<float, float>, 3> bounds = {{{0,1}, {1,2}, {2,3}}};
std::array<Variable, 3> res { {
{0, strings[0], bounds[0]},
{1, strings[1], bounds[1]},
{2, strings[2], bounds[2]}
} };
return res;
}();
Since C++14, std::tuple's constructors are constexpr (at least the ones not accepting allocators), so you could use one of those instead of the assignment operator.
Start adding a constexpr constructor to your class
struct Variable
{
size_t index{};
std::string_view name{};
std::tuple<float, float> bounds{};
constexpr Variable(size_t i, std::string_view str)
: index{i}, name{str}, bounds{i, i + 1} {}
};
Then, you could construct the array using a couple of template functions taking advantage of std::integer_sequence.
template <class Element, std::size_t... I, typename... ArgsType>
constexpr auto make_array_with_indices_impl(std::index_sequence<I...>, ArgsType... args)
{
return std::array<Element, sizeof...(args)>{
Element(I, args)...
};
}
template <class Element, typename... ArgsType>
constexpr auto make_array_with_indices(ArgsType... args)
{
return make_array_with_indices_impl<Element>(
std::index_sequence_for<ArgsType...>{}, args...
);
}
Here an example of their usage.

Eigen, function of RowXpr

I am using Eigen, and am currently trying to write a function to operate on rows of a matrix. I've followed the guidelines in the docs but nothing I try compiles (with either clang or g++); I'm at my wits end. How should one actually write functions which will take a RowXpr?
For reference, here is what I have tried so far:
#include <iostream>
#include <Eigen/Core>
using namespace std;
using namespace Eigen;
constexpr Eigen::StorageOptions Order = ColMajor;
using vect_t = Matrix<double, 1, 3, Order>;
using matr_t = Matrix<double, Dynamic, 3, Order>;
#define FUNC 3
#if FUNC == 1
vect_t func(const vect_t& f)
{
return f;
}
#elif FUNC == 2
vect_t func(const Ref<vect_t>& f)
{
return f;
}
#elif FUNC == 3
template<class D> vect_t func(const MatrixBase<D>& f)
{
return f;
}
#endif
int main()
{
matr_t M = matr_t::Random(5,3);
cout << M << endl;
cout << func( M.row(2) ) << endl;
return 0;
}
Thanks!
Edit:
With clang (version 3.8.0-2ubuntu4) the error I get is as below. The error is comparable with g++.
dan#dan-laptop:~/workspace/scratch$ clang++ eigen_func_test.cpp -I /home/dan/Downloads/eigen_3.3.3/ --std=c++11 && ./a.out
In file included from eigen_func_test.cpp:2:
In file included from /home/dan/Downloads/eigen_3.3.3/Eigen/Core:436:
/home/dan/Downloads/eigen_3.3.3/Eigen/src/Core/PlainObjectBase.h:899:7: error: static_assert failed
"INVALID_MATRIX_TEMPLATE_PARAMETERS"
...EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, (Options&RowMajor)==RowMajor)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/dan/Downloads/eigen_3.3.3/Eigen/src/Core/util/StaticAssert.h:32:40: note: expanded from macro
'EIGEN_STATIC_ASSERT'
#define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG);
^ ~
/home/dan/Downloads/eigen_3.3.3/Eigen/src/Core/PlainObjectBase.h:535:7: note: in instantiation of member function
'Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 0, 1, 3> >::_check_template_params' requested here
_check_template_params();
^
/home/dan/Downloads/eigen_3.3.3/Eigen/src/Core/Matrix.h:379:9: note: in instantiation of function template
specialization 'Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 0, 1, 3>
>::PlainObjectBase<Eigen::Block<Eigen::Matrix<double, -1, 3, 0, -1, 3>, 1, 3, false> >' requested here
: Base(other.derived())
^
eigen_func_test.cpp:32:9: note: in instantiation of function template specialization 'Eigen::Matrix<double, 1, 3, 0,
1, 3>::Matrix<Eigen::Block<Eigen::Matrix<double, -1, 3, 0, -1, 3>, 1, 3, false> >' requested here
return f;
^
eigen_func_test.cpp:41:10: note: in instantiation of function template specialization
'func<Eigen::Block<Eigen::Matrix<double, -1, 3, 0, -1, 3>, 1, 3, false> >' requested here
cout << func( M.row(2) ) << endl;
^
1 error generated.
If you read the part highlighted by clang
EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, (Options&RowMajor)==RowMajor)
you see that, if a matrix has one row at compile time and more than one column, it must be RowMajor. That means, if you set Order = RowMajor or just leave out the , Order in
using vect_t = Matrix<double, 1, 3, Order>;
your code should compile fine (it looks like everything else are just follow-up errors).
Not exactly sure what is causing your compiler error directly but from what you have shown in your source code as well as your compiler errors. This is the part of the compiler error message that I'm basing this off of.
/home/dan/Downloads/eigen_3.3.3/Eigen/src/Core/PlainObjectBase.h:899:7: error: static_assert failed
"INVALID_MATRIX_TEMPLATE_PARAMETERS"
So when looking at the source code you are trying to use the #define func3
that you have declared as such:
template<class D> vect_t func(const MatrixBase<D>& f) {
return f;
}
with the using directives that you have declared as:
constexpr Eigen::StorageOptions Order = ColMajor;
using vect_t = Matrix<double, 1, 3, Order>;
using matr_t = Matrix<double, Dynamic, 3, Order>;
So let's expand this to the full form to see what the compiler is trying to parse or deduce as your parameters and return type.
template<class D>
Matrix<double, 1, 3, constexpr Eigen::StorageOptions Order = ColMajor>
func( const MatrixBase<D>& f ) {
return f;
}
Then in your main you use this with:
int main() {
// matr_t M = matr_t::Random(5,3);
Matrix<double, Dynamic, 3, constexpr Eigen::StorageOptions Order = ColMajor> M
= Matrix<double, Dynamic, 3, constexpr Eigen::StorageOptions Order = ColMajor>::Random(5, 3);
// Then you call your function passing it this:
std::cout << func( M.row(2) ) << std::endl;
return 0;
}
func() is returning Matrix<double, 1, 3, Order>;
and it takes const MatrixBase<D>&
however it appears you are passing it: M.row(2)
that is constructed from: Matrix<double, Dynamic, 3, constexpr Eigen::StorageOptions Order = ColMajor>::Random(5, 3)
In the function itself you are returning f which happens to be
the function's const ref of MatrixBase<D> parameter yet the declaration is expecting to return a Matrix<double, 1, 3, Order>
So I think the compiler is having a hard time trying to convert a
Matrix<double, Dynamic, 3, Order> to a Matrix<double, 1, 3, Order>
Maybe this will help you to understand the compiler error a little better; as you can see when you look at the rest of the compilation error message you can tell that this is evident when it is trying to do the specializations of this template.

Why is my initializer list semi-ignored for type deduction?

Consider the following code:
#include <unordered_map>
#include <iostream>
#include <vector>
template <typename Container, typename... Containers>
inline Container get_union(
const Container& c1,
const Containers&... more_containers)
{
Container result(c1);
auto f = [&result](const Container& c) {
result.insert(std::begin(c), std::end(c));
};
[](...){}(( f(more_containers), 0)...);
return result;
}
int main()
{
std::unordered_map<int, int> m1 = { {1, 2}, {3, 4} };
decltype(m1) m2 = get_union(m1, { {5, 6}, {7, 8} } );
std::cout << "m2.size() = " << m2.size() << "\n'";
return 0;
}
When I try to build this, I get (coliru link):
g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp: In function 'int main()':
main.cpp:21:56: error: too many arguments to function 'Container get_union(const Container&, const Containers& ...) [with Container = std::unordered_map<int, int>; Containers = {}]'
decltype(m1) m2 = get_union(m1, { {5, 6}, {7, 8} } );
^
main.cpp:6:18: note: declared here
inline Container get_union(
^~~~~~~~~
Why is the compiler choosing the empty type-pack for Containers type, if that causes an error?
Quote from list initialization on cppreference:
A braced-init-list is not an expression and therefore has no type, e.g. decltype({1,2}) is ill-formed. Having no type implies that template type deduction cannot deduce a type that matches a braced-init-list, so given the declaration template<class T> void f(T); the expression f({1,2,3}) is ill-formed.
Why is the compiler choosing the empty type-pack for Containers type
Due to how template parameter packs can be ambiguous, there are two possible ways this could be interpreted (I think). Since neither is well-formed, I'm not sure if standard even dictates which interpretation is correct.
Either the parameter pack has size 1 in which case that single type would be deduced from braced-init-list which is ill-formed.
Or, since nothing with a type was passed beyond the first argument, an empty parameter pack is the only possible allowed deduced type for Containers. Now, since the deduced function only accepts a single argument, the braced-init-list is too much. This is how the compiler chose to interpret.
Fundamentally, the problem is that you're attempting a circular deduction. You're apparently trying to deduce Containers from something whose type would be deduced from whatever Containers is - if it wasn't an empty pack.
You cannot deduce from {} when calling a function.
template <typename Container, typename... Containers>
inline Container get_union(
Container c1,
std::initializer_list<Container> more_containers)
{
for (auto&& c:more_containers)
c1.insert( std::begin(c), std::end(c) );
return c1;
}
then call like:
auto m2 = get_union(m1, { { {5, 6}, {7, 8} } } );
live example

how to decide by 'int' type of 'vector<int>' in C++?

I can use enable_if to separate behavior by parameter type such as:
std::vector<int>
Now I want to separate behavior by the inner type of a container:
int of std::vector<int>
what can I do in c++?
I wonder if this is what you mean:
#include<iostream>
#include<vector>
#include<type_traits>
// The following function will display the contents of the provided T
// only if its value_type trait is of type int.
template<typename T>
typename std::enable_if<
std::is_same<typename T::value_type, int>::value,
void>::type display(const T& data) {
std::cout<<"Some ints:"<<std::endl;
for(int xi : data) {
std::cout<<xi<<" ";
}
std::cout<<std::endl;
}
int main() {
std::vector<int> dint = {1, 2, 3, 4, 5, 6};
display(dint);
std::vector<float> dfloat = {1, 2, 3, 4, 5, 6};
// The following call would lead to compile-time error, because
// there is no display function activated for float types:
//display(dfloat);
return 0;
}
Compiling with g++ example.cpp -std=c++11 -Wall -Wextra (OS X 10.7.4 using GCC 4.8.1) yields:
$ ./a.out
Some ints:
1 2 3 4 5 6
As expected, if I uncomment the display(dfloat) line the compiler error message includes:
error: no matching function for call to ‘display(std::vector<float>&)’
Something like the following, where you can fill in int, double, etc. for S?
std::vector<std::enable_if<std::is_same<T, S>::value, S>::type>