C++14 and stdlibs - std::sort(a,b,std::function)

Hi there,

I have compiled ROOT using cmake -Dcxx14=on (Ubuntu 16.04 LTS). It compiles fine and seemed to work fine.

Only “small” problem: ROOT doesn’t compile my code any more. It all boils down to the following short code fragment (used to be a function to sort bins in a histogram, now reduced to almost nothing) with a std::function as compare function argument to std::sort:

#include <algorithm> 
#include <functional> 
#include <vector> 
  
using namespace std; 
  
void doesntCompile(std::function<bool(int, int)> compare) { 
    vector<int> order(20); 
    sort(begin(order), end(order), compare); 
} 
  
int main() { 
    doesntCompile([](int a, int b) { return a < b; }); 
}

I found out that this compiles with clang -std=c++11 and g++ -std=11/14/17. When using clang and -std=c++14/17, it doesn’t compile - well, it DOES compile as soon as you add -stdlib=libc++. You can check at https://godbolt.org/g/LUrjo1

My question is, how can I get ROOT to compile this code, it compiles neither with .L file+ nor without +. Can I somehow use libc++ or will that introduce other problems? Is it a bug in clang and thus in ROOT?

Hi behrenhoff,
what version of ROOT are you on and how did you compile it?
I can interpret a macro that executes your code with ROOT master.

Sorry for the delay in replying, I checked this problem twice more, a) on a VirutalBox where I installed Ubuntu from scratch and b) using the prebuilt docker container ubuntu:16.04.

ROOT version = 6.10.02 (latest production)
Compiled with cmake -Dcxx14=on -Dimt=on "../root-$ROOTVERSION"

root -b -q above-script.C gives (you can also use above-script.C+):

root@c3cb0748db6e:/root-build# root -b -q /x/root-sort-function.C 
   ------------------------------------------------------------
  | Welcome to ROOT 6.10/02                http://root.cern.ch |
  |                               (c) 1995-2017, The ROOT Team |
  | Built for linuxx8664gcc                                    |
  | From tag v6-10-02, 6 July 2017                             |
  | Try '.help', '.demo', '.license', '.credits', '.quit'/'.q' |
   ------------------------------------------------------------


Processing /x/root-sort-function.C...
In file included from input_line_2:2:
In file included from /usr/include/c++/5/string:40:
In file included from /usr/include/c++/5/bits/char_traits.h:39:
In file included from /usr/include/c++/5/bits/stl_algobase.h:71:
/usr/include/c++/5/bits/predefined_ops.h:123:31: error: indirection requires pointer operand ('int' invalid)
        { return bool(_M_comp(*__it1, *__it2)); }
                              ^~~~~~
/usr/include/c++/5/type_traits:2346:7: note: in instantiation of function template specialization '__gnu_cxx::__ops::_Iter_comp_iter<std::function<bool (int, int)> >::operator()<int, int>' requested here
      std::declval<_Fn>()(std::declval<_Args>()...)
      ^
/usr/include/c++/5/type_traits:2357:24: note: while substituting deduced template arguments into function template '_S_test' [with _Fn = __gnu_cxx::__ops::_Iter_comp_iter<std::function<bool (int, int)> >, _Args = (no value)]
      typedef decltype(_S_test<_Functor, _ArgTypes...>(0)) type;
                       ^
/usr/include/c++/5/type_traits:2362:14: note: in instantiation of template class 'std::__result_of_impl<false, false, __gnu_cxx::__ops::_Iter_comp_iter<std::function<bool (int, int)> >, int, int>' requested here
    : public __result_of_impl<
             ^
/usr/include/c++/5/functional:1981:35: note: in instantiation of template class 'std::result_of<__gnu_cxx::__ops::_Iter_comp_iter<std::function<bool (int, int)> > (int, int)>' requested here
               typename _Res2 = typename result_of<_Func(_ArgTypes...)>::type>
                                         ^
/usr/include/c++/5/functional:2053:30: note: in instantiation of default argument for '_Callable<__gnu_cxx::__ops::_Iter_comp_iter<std::function<bool (int, int)> > >' required here
               typename = _Requires<_Callable<_Functor>, void>>
                                    ^~~~~~~~~~~~~~~~~~~
/usr/include/c++/5/functional:2054:2: note: in instantiation of default argument for 'function<__gnu_cxx::__ops::_Iter_comp_iter<std::function<bool (int, int)> >, void>' required here
        function(_Functor);
        ^~~~~~~~
/usr/include/c++/5/bits/predefined_ops.h:130:14: note: while substituting deduced template arguments into function template 'function' [with _Functor = __gnu_cxx::__ops::_Iter_comp_iter<std::function<bool (int, int)> >, $1 = (no value), $2 = (no value)]
    { return _Iter_comp_iter<_Compare>(__comp); }
             ^
/usr/include/c++/5/bits/stl_algo.h:4729:54: note: in instantiation of function template specialization '__gnu_cxx::__ops::__iter_comp_iter<std::function<bool (int, int)> >' requested here
      std::__sort(__first, __last, __gnu_cxx::__ops::__iter_comp_iter(__comp));
                                                     ^
/x/root-sort-function.C:9:5: note: in instantiation of function template specialization 'std::sort<__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >, std::function<bool (int, int)> >' requested here
    sort(begin(order), end(order), compare);

To reproduce (I was too lazy to create a real dockerfile) run the following script in docker:

#!/bin/bash
# run from outside docker (from the directory containing this script):
# docker run -t -i -v "$(pwd):/x:ro" ubuntu:16.04 /bin/bash
# then execute /x/this-script.sh

set -ex
ROOTVERSION=6.10.02
download="https://root.cern.ch/download/root_v${ROOTVERSION}.source.tar.gz"

apt update
apt -y install wget perl python git dpkg-dev make g++ gcc binutils libx11-dev libxpm-dev libxft-dev libxext-dev libpcre3-dev cmake
apt clean

wget -c "$download"
tar xzf "root_v${ROOTVERSION}.source.tar.gz"
# rm "root_v${ROOTVERSION}.source.tar.gz"

mkdir root-build
cd root-build
cmake -Dcxx14=on -Dimt=on "../root-$ROOTVERSION"
cmake --build . -- -j10

then source bin/thisroot.sh and run root -b -q /x/above-script.C

Alright, this is very helpful thank you. I will try to reproduce the problem, and then I will probably report it to someone more competent than me :smiley:

Very interesting: I tried to compile root on Ubuntu 17.04 (just change the base image in docker). No problems there.

So the problem seems to originate from the stdlibc++. If you look at the godbolt link above and add -stdlib=libc++, clang compiles the code correctly. Unfortunately, my knowledge about C++ and the differences between libc++ and stdlib++ ends here. No idea how to change that in ROOT…

So maybe no root with C++14 on Ubuntu 16.04 LTS? Or can one just update the stdlibc++?

Hi, your problem seems to be related to a mismatch between the compiler and the standard library headers.
The error comes from a header file that probably belongs to libc++ (coming from /usr/include/c++ rather than from you compiler’s own standard library implementation). I believe that’s why when you add -stdlib=libc++ it solves your problem. I don’t think this is really an issue with ROOT per se, but just a configuration problem of the compiler. Maybe ROOT should just add -stdlib=libc++ to root-config --cflags when clang is using that as its own standard library. For now, you can just add that by hand as you mentioned to work around the problem.

How do I do that?! Where exactly do I specify that switch? To clarify: I don’t have that problem when compiling with g++, just when executing the macro in ROOT.
root -stdlib=libc++ -b -q /x/root-sort-function.C doesn’t work.

Cannot reproduce on Debian 8 and ROOT master (compiled with -Dcxx14=ON -Dtesting=ON -Droottest=ON and nothing else).

Correct me if I am wrong: what we know so far is that the problem seems to be specific of the libstdc++ that comes with Ubuntu 16.04, and is due to some bad interaction of clang and rootcling with that libstdc++, but only when compiling with -std=c++14. Playing with your godbolt link shows that the issue is not present in clang 4.0, and can be worked around in precedent versions by specifying -stdlib=libc++.

If this is the case, updating clang or Ubuntu version solves the problem, and passing -stdlib=libc++ to rootcling would solve the problem in the broken configuration – except I don’t know how to pass flags to cling :sweat_smile: @vassilis maybe can help here.

(as a super small side note -Dimt=ON is the default in 6.10 and master so you do not need to specify it when you build)

I just tried with master (From heads/master@v6-09-02-1734-g73b3cb1, Jul 20 2017, 12:50:37) under Ubuntu 16.04 - it works!

So I found a problem that only occurs in <=6.10.x with a certain stdlibc++. Is is already fixed - either when updating stdlibc++ or ROOT. Good, no action item needed!

Super super side node: I was looking at Building ROOT from source - ROOT where it is listed as OFF by default. :stuck_out_tongue_winking_eye:

Hi,

follow-up:

  • I’ll correct the -Dimt default value on the website asap, thank you.
  • @vassilis tells me that passing -stdlib=libc++ to cling was a very bad idea (would cause obscure compatibility problems between compiled and interpreted code)
  • he also confirms that the recent update of the llvm/clang version internally used by ROOT evidently has solved the problem, so that’s the end of it
1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.