GCC cannot resolve proper std::accumulate - c++

I'm trying to compile code like this using both GCC 4.4.7 and MSVC 2010:
// test.cpp
// use g++ -c test.cpp to attempt compile this
#include <map>
#include <numeric>
#include <algorithm>
struct A
{
A() : v1(0), v2(0) {}
int v1, v2;
};
typedef std::map<int, A> A_map;
void fill_map(A_map& m); // external function
A process()
{
A_map m;
fill_map(m);
A a;
if(!m.empty())
{
struct Aggregate
{
A operator()(const A& left, const A_map::value_type& right)
{
A result;
result.v1 = left.v1 + right.second.v1;
result.v2 = std::max(left.v2, right.second.v2);
return result;
}
};
A a0;
a = std::accumulate(m.begin(), m.end(), a0, Aggregate());
}
return a;
}
While MSVC2010 compiles this nicely, GCC 4.4.7 gives following error:
test.cpp: In function ‘A process()’:
test.cpp:33: error: no matching function for call to ‘accumulate(std::_Rb_tree_iterator<std::pair<const int, A> >, std::_Rb_tree_iterator<std::pair<const int, A> >, A&, process()::Aggregate)’
Any ideas why so and how to fix this?
Ideas like completely rewrite code using C++11 lambdas do not work - need exactly this code.

C++03 does not allow for the instantiation of templates with local types. If you can't use C++11 or C++14, you can fix that problem by moving the definition of Aggregate outside of the process function. For good measure, make its operator() a const member.
#include <map>
#include <numeric>
#include <algorithm>
struct A
{
A() : v1(0), v2(0) {}
int v1, v2;
};
struct Aggregate
{
A operator()(const A& left, const A_map::value_type& right) const
{
....
}
};
void fill_map(A_map& m); // external function
A process()
{
....
}

Related

What's Clang's problem with my code? GCC and MSVC think it's fine

I'm working on an Advent of Code challenge (2021 day 18). Just as a test I tried compiling it on different compilers. While GCC (11.2) and MSVC (19.30) think it's fine, Clang (13.0.0) throws a list of errors. link to compiler explorer
/opt/compiler-explorer/gcc-11.2.0/lib/gcc/x86_64-linux-gnu/11.2.0/../../../../include/c++/11.2.0/bits/alloc_traits.h:514:4: error: no matching function for call to 'construct_at'
std::construct_at(__p, std::forward<_Args>(__args)...);
^~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-11.2.0/lib/gcc/x86_64-linux-gnu/11.2.0/../../../../include/c++/11.2.0/bits/vector.tcc:115:21: note: in instantiation of function template specialization 'std::allocator_traits<std::allocator<RegularNumber>>::construct<RegularNumber, int, Named<int, index_for_vector_of_RegularNumber> &, Named<int, index_for_vector_of_RegularNumber>>' requested here
_Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
^
<source>:115:19: note: in instantiation of function template specialization 'std::vector<RegularNumber>::emplace_back<int, Named<int, index_for_vector_of_RegularNumber> &, Named<int, index_for_vector_of_RegularNumber>>' requested here
regNumVec.emplace_back(*it - '0', leftRegNumIdx,
^
/opt/compiler-explorer/gcc-11.2.0/lib/gcc/x86_64-linux-gnu/11.2.0/../../../../include/c++/11.2.0/bits/stl_construct.h:94:5: note: candidate template ignored: substitution failure [with _Tp = RegularNumber, _Args = <int, Named<int, index_for_vector_of_RegularNumber> &, Named<int, index_for_vector_of_RegularNumber>>]: no matching constructor for initialization of 'RegularNumber'
construct_at(_Tp* __location, _Args&&... __args)
^
What doesn't Clang understand what seems fine according to the other two? Is this a bug, or my mistake?
Here's the "minimalized" code:
#include <algorithm>
#include <concepts>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <type_traits>
#include <utility>
#include <variant>
#include <vector>
template <typename Type, typename Description>
class Named {
public:
using UnderlyingType = Type;
// clang-format off
constexpr Named()
noexcept(std::is_nothrow_default_constructible_v<Type>)
requires std::default_initializable<Type>
= default;
explicit constexpr Named(Type const &val)
noexcept(std::is_nothrow_copy_constructible_v<Type>)
requires std::copyable<Type>
: val_{val}
{}
explicit constexpr Named(Type&& val)
noexcept(std::is_nothrow_move_constructible_v<Type>)
requires std::movable<Type>
: val_{std::move(val)}
{}
constexpr operator Type() const&
noexcept(std::is_nothrow_copy_constructible_v<Type>)
requires std::copyable<Type>
{
return val_;
}
constexpr operator Type() const&&
noexcept(std::is_nothrow_move_constructible_v<Type>) // move assignable?
requires std::movable<Type>
{
return std::move(val_);
}
private:
Type val_;
};
// clang-format on
template <typename T>
auto readinputdata(std::istream &&is) {
auto data{std::vector<T>{}};
copy(std::istream_iterator<T>{is}, std::istream_iterator<T>{},
back_inserter(data));
return data;
}
static constexpr auto testData{
"[[[0,[5,8]],[[1,7],[9,6]]],[[4,[1,2]],[[1,4],2]]]\n"
"[[[5,[2,8]],4],[5,[[9,9],0]]]\n"
"[6,[[[6,2],[5,6]],[[7,6],[4,7]]]]\n"
"[[[6,[0,7]],[0,9]],[4,[9,[9,0]]]]\n"
"[[[7,[6,4]],[3,[1,3]]],[[[5,5],1],9]]\n"
"[[6,[[7,3],[3,2]]],[[[3,8],[5,7]],4]]\n"
"[[[[5,4],[7,7]],8],[[8,3],8]]\n"
"[[9,3],[[9,9],[6,[4,9]]]]\n"
"[[2,[[7,7],7]],[[5,8],[[9,3],[0,2]]]]\n"
"[[[[5,2],5],[8,[3,7]]],[[5,[7,5]],[4,4]]]\n"};
struct index_for_vector_of_Pair;
using PairIndex = Named<int, index_for_vector_of_Pair>;
struct index_for_vector_of_RegularNumber;
using RegNumIndex = Named<int, index_for_vector_of_RegularNumber>;
struct RegularNumber {
using IndexType = RegNumIndex;
int value{};
RegNumIndex leftIdx{}, rightIdx{};
};
using IndexVariant = std::variant<PairIndex, RegNumIndex>;
struct Pair {
using IndexType = PairIndex;
PairIndex parent{};
IndexVariant leftIdx{}, rightIdx{};
};
static auto pairVec{std::vector<Pair>{}};
static auto regNumVec{std::vector<RegularNumber>{}};
// used for converting the input strings to pairs
static auto leftRegNumIdx{RegNumIndex{-1}};
static constexpr auto invalid_index{-1};
template <typename Type>
auto get_last_index(std::vector<Type> const &vec) {
using Index = typename Type::IndexType;
return Index{static_cast<typename Index::UnderlyingType>(size(vec))};
}
auto generate_pair(std::string::const_iterator &it, PairIndex parent)
-> PairIndex;
auto generate_side(std::string::const_iterator &it, PairIndex pairIdx)
-> IndexVariant {
if (*it == '[') {
return generate_pair(it, pairIdx);
} else {
regNumVec.emplace_back(*it - '0', leftRegNumIdx, // error on this line
RegNumIndex{invalid_index});
auto const litIdx{get_last_index(regNumVec)};
if (leftRegNumIdx != invalid_index) {
regNumVec[leftRegNumIdx].rightIdx = litIdx;
}
leftRegNumIdx = litIdx;
return litIdx;
};
}
auto generate_pair(std::string::const_iterator &it,
PairIndex parent = PairIndex{invalid_index}) -> PairIndex {
pairVec.emplace_back();
auto const pairIdx{get_last_index(pairVec)};
auto &pair{pairVec.back()};
pair.parent = parent;
++it; // skip [
pair.leftIdx = generate_side(it, pairIdx);
++it; // skip comma
pair.rightIdx = generate_side(it, pairIdx);
++it; // skip ]
return pairIdx;
}
int main() {
auto const snailFishNumbers{readinputdata<std::string>( //
std::stringstream{testData} //
)};
auto const outerPairIdxs{[&] {
auto outerPairIdxs{std::vector<PairIndex>{}};
outerPairIdxs.reserve(size(snailFishNumbers));
transform(cbegin(snailFishNumbers), cend(snailFishNumbers),
back_inserter(outerPairIdxs), [](auto const &str) {
auto it{cbegin(str)}; // need lvalue
return generate_pair(it);
});
return outerPairIdxs;
}()};
return 0;
}
Your type is an aggregate
struct RegularNumber {
using IndexType = RegNumIndex;
int value{};
RegNumIndex leftIdx{}, rightIdx{};
};
which construct_at tries to initialize with round parenthesis
::new(std::declval<void*>()) T(std::declval<Args>()...).
However, an aggregate needs a {} initializer, until the compiler implements P0960 Allow initializing aggregates from a parenthesized list of values
And Clang just isn't there yet. Compiler support for C++20

Why is copying needed when using initializer lists with std::array

This is a follow-up to How to initialize std::array member in constructor initialization list when the size of the array is a template parameter. I got a great answer, but still I have an issue with g++/clang++ for my use case (program builds fine with msvc).
It looks like using the initializer list + index_sequence to initialize a std::array containing a class Hash with a deleted copy constructor fails, even if the initializer list does not contain the Hash class itself, but parameters to construct it. Unfortunately in my actual use case the copy constructor is not available because the class contains a mutex.
When building the following program, I have this error:
$ g++ -std=c++14 -c index_sequence.cxx
index_sequence.cxx: In instantiation of ‘A<H, N>::A(const std::vector<int>&, std::index_sequence<i ...>) [with long unsigned int ...i = {0ul, 1ul, 2ul, 3ul}; H = Hash; long unsigned int N = 4ul; std::index_sequence<i ...> = std::integer_sequence<long unsigned int, 0ul, 1ul, 2ul, 3ul>]’:
index_sequence.cxx:24:71: required from ‘A<H, N>::A(const std::vector<int>&) [with H = Hash; long unsigned int N = 4ul]’
index_sequence.cxx:37:22: required from here
index_sequence.cxx:28:86: error: use of deleted function ‘Hash::Hash(const Hash&)’
A(const vector<int> &data, std::index_sequence<i...>) : hashes{((void)i, data)...} {}
and here is the program:
#include <vector>
#include <array>
#include <utility>
using namespace std;
struct Hash {
const vector<int> &data;
Hash(const vector<int> &data)
: data(data) {
}
Hash(const Hash &) = delete;
uint64_t operator()(int id) const {
return data[id];
}
};
template <class H, size_t N>
class A {
public:
A(const vector<int> &data) : A(data, std::make_index_sequence<N>{}) {
}
template <std::size_t... i>
A(const vector<int> &data, std::index_sequence<i...>) : hashes{((void)i, data)...} {}
std::array<H, N> hashes;
};
int main () {
vector<int> data{1, 2, 3, 4};
A<Hash, 4> a{data};
}
Since the same program builds fine with msvc, I wonder if this is an issue with g++'s std::array initializer_list support?

operator== does not compile if I include <iostream>

The following code compiles perfectly if:
I don't include <iostream> or
I name operator== as alp::operator==.
I suppose there is a problem with <iostream> and operator==, but I don't know what.
I compile the code with gcc 7.3.0, clang++-6.0 and goldbolt. Always the same error.
The problem is that the compiler is trying to cast the parameters of operator== to const_iterator, but why? (I suppose the compiler doesn't see my version of operator==, and looks for other versions).
#include <vector>
#include <iostream> // comment and compile
namespace alp{
template <typename It_base>
struct Iterator {
using const_iterator = Iterator<typename It_base::const_iterator>;
operator const_iterator() { return const_iterator{}; }
};
template <typename It_base>
bool operator==(const Iterator<It_base>& x, const Iterator<It_base>& y)
{ return true;}
}// namespace
struct Func{
int& operator()(int& p) const {return p;}
};
template <typename It, typename View>
struct View_iterator_base{
using return_type = decltype(View{}(*It{}));
using const_iterator =
View_iterator_base<std::vector<int>::const_iterator, Func>;
};
using view_it =
alp::Iterator<View_iterator_base<std::vector<int>::iterator, Func>>;
int main()
{
view_it p{};
view_it z{};
bool x = operator==(z, p); // only compiles if you remove <iostream>
bool y = alp::operator==(z,p); // always compile
}
Error message:
yy.cpp: In instantiation of ‘struct View_iterator_base<__gnu_cxx::__normal_iterator<const int*, std::vector<int> >, Func>’:
yy.cpp:9:73: required from ‘struct alp::Iterator<View_iterator_base<__gnu_cxx::__normal_iterator<const int*, std::vector<int> >, Func> >’
yy.cpp:44:29: required from here
yy.cpp:28:42: error: no match for call to ‘(Func) (const int&)’
using return_type = decltype(View{}(*It{}));
~~~~~~^~~~~~~
yy.cpp:22:10: note: candidate: int& Func::operator()(int&) const <near match>
int& operator()(int& p) const {return p;}
^~~~~~~~
yy.cpp:22:10: note: conversion of argument 1 would be ill-formed:
yy.cpp:28:42: error: binding reference of type ‘int&’ to ‘const int’ discards qualifiers
using return_type = decltype(View{}(*It{}));
~~~~~~^~~~~~~
I've made a more minimal test case here: https://godbolt.org/z/QQonMG .
The relevant details are:
A using type alias does not instantiate a template. So for example:
template<bool b>
struct fail_if_true {
static_assert(!b, "template parameter must be false");
};
using fail_if_used = fail_if_true<true>;
will not cause a compile time error (if fail_if_used isn't used)
ADL also inspects template parameter classes. In this case, std::vector<int>::iterator is __gnu_cxx::__normal_iterator<const int*, std::vector<int> >, Func>, which has a std::vector<int> in it's template. So, operator== will check in the global namespace (always), alp (As alp::Iterator is in alp), __gnu_cxx and std.
Your View_iterator_base::const_iterator is invalid. View_iterator_base::const_interator::result_type is defined as decltype(Func{}(*std::vector<int>::const_iterator{})). std::vector<int>::const_iterator{} will be a vectors const iterator, so *std::vector<int>::const_iterator{} is a const int&. Func::operator() takes an int&, so this means that the expression is invalid. But it won't cause a compile time error if not used, for the reasons stated above. This means that your conversion operator is to an invalid type.
Since you don't define it as explicit, the conversion operator (To an invalid type) will be used to try and match it to the function parameters if they don't already match. Obviously this will finally instantiate the invalid type, so it will throw a compile time error.
My guess is that iostream includes string, which defines std::operator== for strings.
Here's an example without the std namespace: https://godbolt.org/z/-wlAmv
// Avoid including headers for testing without std::
template<class T> struct is_const { static constexpr const bool value = false; } template<class T> struct is_const<const T> { static constexpr const bool value = true; }
namespace with_another_equals {
struct T {};
bool operator==(const T&, const T&) {
return true;
}
}
namespace ns {
template<class T>
struct wrapper {
using invalid_wrapper = wrapper<typename T::invalid>;
operator invalid_wrapper() {}
};
template<class T>
bool operator==(const wrapper<T>&, const wrapper<T>&) {
return true;
}
}
template<class T>
struct with_invalid {
static_assert(!is_const<T>::value, "Invalid if const");
using invalid = with_invalid<const T>;
};
template<class T>
void test() {
using wrapped = ns::wrapper<with_invalid<T>>;
wrapped a;
wrapped b;
bool x = operator==(a, b);
bool y = ns::operator==(a, b);
}
template void test<int*>();
// Will compile if this line is commented out
template void test<with_another_equals::T>();
Note that just declaring operator const_iterator() should instantiate the type. But it doesn't because it is within templates. My guess is that it is optimised out (where it does compile because it's unused) before it can be checked to show that it can't compile (It doesn't even warn with -Wall -pedantic that it doesn't have a return statement in my example).

Overload rules for multiple, templated constructors in list initialization

I'm unsure if the following code is valid according to the c++11 standard and should have the same behavior across different implementations or not:
#include <cstddef>
struct Foo{
template <std::size_t N>
constexpr Foo( const char ( &other )[N] )
{}
template <class T>
constexpr Foo( const T* const& other ) = delete;
};
struct Bar {
Foo a;
int b;
};
int main() {
Bar bar{ "Hello",5};
}
The general Idea is to allow the construction from a string literal and a std::string (not shown here), but not from a pointer to const char, which is somewhat tricky (discussed in this question).
Newer versions of g++ (>=6.0) and almost all clang++ versions(>=3.4) seem to compile this just fine, but e.g. with g++-4.8 -std=c++11 main.cpp I get the following error:
main.cpp: In function ‘int main()’:
main.cpp:17:27: error: use of deleted function ‘constexpr Foo::Foo(const T* const&) [with T = char]’
Bar bar{ "Hello",5};
So my question is:
Does the standard require a certain behavior for this code at all and if so, who is right?
Enclosing the initalizer in {} worked for me, like this:
#include <cstddef>
struct Foo {
template<std::size_t N>
constexpr Foo(const char (&)[N]) {}
template<class T>
constexpr Foo(const T* const&) = delete;
};
struct Bar {
Foo a;
int b;
};
int main() {
Bar bar{ {"Hello"}, 5 };
// ^^^^^^^^^
(void)bar;
}
I tested it on wandbox with GCC 4.8.1
https://wandbox.org/permlink/1TJF2NyT7mrKkqQ0
GCC is not necessarily incorrect here, I vaguely recall
a defect report regarding this.

A piece of code cannot be compiled by intel compiler but clang will compile it

The following code is a minimum working (or perhaps non-working) example.
What it does is basically encapsulates a bunch of std::map structures as private members in a base class. To avoid writing a lot of setters and getters, they are implemented as template functions.
// test.cpp
#include <map>
#include <iostream>
enum class E0
{
F0, F1, F2,
};
The declaration of the base class.
using std::map;
class P_base
{
private:
map<E0, int> m_imap;
// ...
// ... Other std::map members with different key types and value types.
public:
map<E0, int> & imap;
// ...
// ... Other std::map references.
P_base() : imap(m_imap) {}
template<typename map_type, typename key_type, typename val_type>
void set(map_type & m, const key_type & k, const val_type & v)
{
m[k] = v;
}
template<typename map_type, typename key_type>
auto access_to_map(const map_type & m, const key_type & k) -> decltype(m.at(k))
{
return m.at(k);
}
};
class P : private P_base
{
public:
decltype(P_base::imap) & imap;
P() : P_base(), imap(P_base::imap) {}
template<typename map_type, typename key_type, typename val_type>
void set(map_type & m, const key_type & k, const val_type & v)
{
P_base::set(m, k, v);
}
template<typename map_type, typename key_type>
auto access_to_map(const map_type & m, const key_type & k) -> decltype(P_base::access_to_map(m, k))
{
return P_base::access_to_map(m, k);
}
};
main
int main(int argc, const char * argv[])
{
using std::cout;
using std::endl;
P op;
op.set(op.imap, E0::F0, 100);
op.set(op.imap, E0::F1, 101);
op.set(op.imap, E0::F2, 102);
cout << op.access_to_map(op.imap, E0::F1) << endl;
}
$ clang++ -std=c++11 test.cpp && ./a.out
101
But if I compile it with intel compiler (icpc version 15.0.3 (gcc version 5.1.0 compatibility)), the compiler gives me this error message (which I don't undertand at all, especially when clang will compile the code):
$ icpc -std=c++ test.cpp && ./a.out
test.cpp(67): error: no instance of function template "P::access_to_map" matches the argument list
argument types are: (std::__1::map<E0, int, std::__1::less<E0>, std::__1::allocator<std::__1::pair<const E0, int>>>, E0)
object type is: P
cout << op.access_to_map(op.imap, E0::F1) << endl;
And it also confuses me by not complaining about the set function.
Does anyone have any idea what is going on here?
Note: My answer applies to g++ - hopefully it's the same as icc.
Here is a smaller test case:
struct Base
{
int func(int t) { return t; }
};
struct Der : Base
{
template<typename T>
auto f(T t) -> decltype(Base::func(t))
{
return t;
}
};
int main(){ Der d; d.f(5); }
The error is:
mcv.cc: In function 'int main()':
mcv.cc:16:25: error: no matching function for call to 'Der::f(int)'
int main(){ Der d; d.f(5); }
^
mcv.cc:16:25: note: candidate is:
mcv.cc:9:7: note: template<class T> decltype (t->Base::func()) Der::f(T)
auto f(T t) -> decltype(Base::func(t))
^
mcv.cc:9:7: note: template argument deduction/substitution failed:
mcv.cc: In substitution of 'template<class T> decltype (t->Base::func()) Der::f(T) [with T = int]':
mcv.cc:16:25: required from here
mcv.cc:9:38: error: cannot call member function 'int Base::func(int)' without object
auto f(T t) -> decltype(Base::func(t))
This can be fixed by changing decltype(Base::func(t)) to decltype(this->Base::func(t)). A corresponding fix fixes your code sample, for me.
Apparently, the compiler doesn't consider that Base::func(t) should be called with *this as hidden argument. I don't know if this is a g++ bug, or if clang is going beyond the call of duty.
Note that in C++14, since the function has a single return statement, the trailing return type can be omitted entirely:
template<typename T>
auto f(T t)
{
return t;
}