C++ MSVC/GCC/Clang compilers bug - c++

I discovered what appears to be a mind breaking bug in the 3 compilers from the title. The following code compiles with the latest versions of all three compilers using both the c++11 and c++14 standards, even though it really shouldn't as the "visit_detail" function is not visible to "main".
Correction: I was stupid, not actually a bug in GCC/Clang, seems to be a bug in my MSVC version tho.
#include <utility>
#include <iostream>
#include <type_traits>
namespace bug
{
using namespace std;
using size_t = unsigned long long;
namespace detail
{
struct visit_stop_t {};
constexpr bug::detail::visit_stop_t visit_stop = bug::detail::visit_stop_t();
template <typename Visitor, typename First, typename... Tail>
void visit_detail(Visitor&& vis, First&& first, Tail&&... tail)
{
// code, not necessairy to recreate bug
}
}
template <typename Visitor, typename... Variants>
void visit(Visitor&& vis, Variants&&... vars)
{
bug::detail::visit_detail(bug::forward<Visitor>(vis), bug::forward<Variants>(vars)..., bug::detail::visit_stop);
}
template <typename Visitor>
void visit(Visitor&& vis) = delete;
}
using namespace bug;
// dummy variant, used to test the code
// code is never actually used in this version
template <typename... T>
struct variant
{
static constexpr bug::size_t size() noexcept { return sizeof...(T); }
constexpr variant(int) noexcept {}
template <bug::size_t I>
constexpr int get() const noexcept { return 5; }
};
// simple example visitor
// code is never actually used in this version
struct visitor
{
int operator()(int x) { std::cout << x << std::endl; return x; }
double operator()(double x) { std::cout << x << std::endl; return x; }
};
int main()
{
visitor vis;
variant<int, double> var = 5;
// where the trouble is:
visit_detail(vis, var, bug::detail::visit_stop); // ADL: http://en.cppreference.com/w/cpp/language/adl
visit_detail(vis, var); // fails with GCC/Clang, no error with MSVC => MSVC bug maybe
std::cout << "Press enter to continue . . . ";
std::getchar();
return 0;
}

What you're experiencing is a C++ feature called argument-dependent lookup, or ADL for short. Basically, if you invoke a function f without explicitly qualifying it, the compiler will look for f in the namespaces of the arguments that you've passed.
This is what allows operator<< for IO streams to work without requiring qualifications:
std::cout << 100; // finds std::operator<<(std::ostream&, int);
In your particular case, the argument bug::detail::visit_stop is making the compiler look for visit_detail inside the bug::detail namespace.

Related

Call fallback method if method does not exist

I want to be able to do the following in C++
Try to call a function from a namespace, e.g., boost::filesystem::copy
If copy is not a member of boost::filesystem, call a fallback function, e.g., boost::filesystem3::copy
If fallback function does not exist (this could be either because boost does not have member filesystem3, or because boost::filesystem3 does not have member copy), the code should not compile.
After reading loads and loads of extremely long and complicated pieces of code, it is unclear to me what the simple way of doing this would be. A C++11 solution is fine. But the code sometimes requires to compile with an old boost version (1.39.0), which is precisely why this workaround is required.
Currently I do it by creating method alias after checking the BOOST_VERSION macro. But it would be good to know of a more sophisticated alternative that could be applicable for more general cases.
Here is a possible solution with which you can do that.
The only way I found to do that is by polluting the namespaces boost::filesystem and boost::filesystem3, then test if the original function exists. I know that's not the best thing ever, but it's a compromise to have it up and running at the end of the days.
There exist two versions of copy in both the namespaces. They are declared as:
void copy(const path& from, const path& to);
void copy(const path& from, const path& to, system::error_code& ec);
Note that I redeclared them with slightly different forms in the example below to simplify things up and to avoid using boost in the example code.
Here is a minimal, working example:
#include<iostream>
#include<type_traits>
// original namespaces
namespace boost { namespace filesystem {
void copy(int, char) { std::cout << "b::f::copy" << std::endl; }
void copy(int, char, double) {}
// ... everything else ...
}}
namespace boost { namespace filesystem3 {
void copy(int, char) { std::cout << "b::f3::copy" << std::endl; }
void copy(int, char, double) {}
// ... everything else ...
}}
// pollution
namespace boost { namespace filesystem {
struct tag {};
void copy(tag, tag) {}
}}
namespace boost { namespace filesystem3 {
struct tag {};
void copy(tag, tag) {}
}}
std::true_type test(int, void(*)(int, char));
std::false_type test(...);
constexpr bool has_filesystem_copy = decltype(test(0, &boost::filesystem::copy))::value;
constexpr bool has_filesystem3_copy = decltype(test(0, &boost::filesystem3::copy))::value;
template<bool = true>
struct fallback_fn {};
template<>
struct fallback_fn<has_filesystem3_copy> {
template<typename... Args>
static void invoke(Args... args) {
boost::filesystem3::copy(args...);
}
};
template<bool = true>
struct copy_fn: fallback_fn<> {};
template<>
struct copy_fn<has_filesystem_copy> {
template<typename... Args>
static void invoke(Args... args) {
boost::filesystem::copy(args...);
}
};
int main() {
copy_fn<>::invoke(0, 'c');
}
Feel free to play with the functions that are part of those namespaces marked as original namespaces.
To sum up:
If copy is available both in boost::filesystem and boost::filesystem3, the former is picked up. See it on wandbox.
If copy is available only in boost::filesystem, it's picked up. See it on wandbox.
If copy is available only in boost::filesystem3, it's picked up. See it on wandbox.
If copy isn't available at all, you get a compile-time error like this:
'invoke' is not a member of 'copy_fn<>'
See it on wandbox.
To do that I used the rules of template specialization and a couple of constexpr variables.
Note that you can avoid to include <type_traits> by doing this, if you prefer:
constexpr bool test(int, void(*)(int, char)) { return true; }
constexpr bool test(...) { return false; }
constexpr bool has_filesystem_copy = test(0, &boost::filesystem::copy);
constexpr bool has_filesystem3_copy = test(0, &boost::filesystem3::copy);
Again, polluting a namespace isn't the best idea with which you can come up. Anyway it's a viable approach that probably works in this case, as long as you invoke copy through an utility class like copy_fn.
As a side note, keep in mind that it's quite annoying and error-prone if you have to wrap more than one function. It's not the case if I look at the text of your question only, but I don't know what's the real case.
Here's another idea that (mostly) does the trick:
#include <tuple>
#include <utility>
#include <iostream>
namespace fake_boost {
namespace filesystem {
// class path { public:
// template<typename Source> path(Source const&) {}
// };
// void copy( const path&, const path& )
// { std::cout << "fake_boost::filesystem::copy\n"; }
}
namespace filesystem3 {
class path { public:
template<typename Source> path(Source const&) {}
};
void copy( const path&, const path& )
{ std::cout << "fake_boost::filesystem3::copy\n"; }
}
}
namespace test_copy {
template <typename...> using void_t = void; // or use C++17 std::void_t
namespace test_filesystem3 {
using namespace fake_boost::filesystem3;
template <typename... Args>
void do_copy(Args&& ... args)
{ copy(std::forward<Args>(args)...); }
}
namespace test_filesystem {
template <typename Tuple, typename Enable=void>
struct copy_switcher {
template <typename... Args>
static void do_copy(Args&& ... args)
{ test_filesystem3::do_copy(std::forward<Args>(args)...); }
};
using namespace fake_boost::filesystem;
template <typename... Args>
struct copy_switcher<std::tuple<Args...>,
void_t<decltype(copy(std::declval<Args&&>()...))>> {
static void do_copy(Args&& ... args)
{ copy(std::forward<Args>(args)...); }
};
}
}
template <typename... Args>
void do_copy(Args&& ... args) {
test_copy::test_filesystem::copy_switcher<std::tuple<Args...>>
::do_copy(std::forward<Args>(args)...);
}
int main() {
do_copy( "from.txt", "to.txt" );
}
A couple of caveats: The namespaces must actually exist, but you can always define them as empty. The function tested for must not exist at global scope with compatible arguments. In particular, you couldn't rename my last do_copy to just copy.

Clang and GCC different behavior when resolving variadic function template overload

Consider this code:
#include <utility>
int foo_i(int x) { return x + 1; }
char foo_c(char x) { return x + 1; }
using II = int (*)(int);
using CC = char (*)(char);
template<typename F>
struct fn {
F f;
template<typename... Args>
decltype(auto) operator()(Args&&... args) const
{
return f(std::forward<Args>(args)...);
}
};
struct fn_2 : private fn<II>, private fn<CC> {
fn_2(II fp1, CC fp2)
: fn<II>{fp1}
, fn<CC>{fp2}
{}
using fn<II>::operator();
using fn<CC>::operator();
};
int main()
{
fn_2 f(foo_i, foo_c);
f(42);
}
Basically, fn<T> stores a functor (not necessarily a function pointer) of type T, and its variadic operator() forwards everything to the functor.
This code compiles fine with gcc 4.9.2 through gcc 6.1, but is rejected by every clang version I've tried, even clang 3.8. clang complains that the call is ambiguous. (I'd appreciate it if someone can try compile it with VS, because I don't have access to it right now.)
Which compiler is right, and how can I work around this discrepancy?
UPDATE: Although I'm still not sure which compiler's behavior is (more) compliant to the standard, I've found a workaround: Specializing fn<T> on pointers to functions, and avoid the need to blindly use variadic operator(). (Well, we've still left out pointers to member functions... For now I'm going to ignore them. :/) Example:
template<typename F>
struct fn : private F {
using F::operator();
};
template<typename R, typename... Args>
struct fn<R (*)(Args...)> {
fn(R (*f)(Args...)) noexcept : f_(f) {}
R operator()(Args&&... args) const
{
return f_(std::forward<Args>(args)...);
}
private:
R (*f_)(Args...);
};
I think clang is right here to not compile the code as the operator() is clearly ambiguous. If you think about it, from the provided template signature for operator() it's not clear which function should be preferred. You will have to provide additional hints to the compiler based on your stored function in fn.
Here is my solution:
#include <utility>
#include <type_traits>
#include <iostream>
int foo(int x) { return x + 1; }
char foo(char x) { return x + 1; }
using II = int (*)(int);
using CC = char (*)(char);
template <bool... B>
struct bool_pack {};
template <bool... V>
using all_true = std::is_same<bool_pack<true, V...>, bool_pack<V..., true>>;
template <typename... Args> struct packed {};
template <typename T> struct func_traits;
template <typename R, typename... Args>
struct func_traits<R(*)(Args...)> {
using type = packed<Args...>;
};
template<typename F>
struct fn {
F f;
template<typename... Args,
typename std::enable_if<std::is_same<packed<Args...>, typename func_traits<F>::type>::value>::type* = nullptr>
auto operator()(Args&&... args) const
{
return f(std::forward<Args>(args)...);
}
};
struct fn_2 : private fn<II>, private fn<CC> {
fn_2(II fp1, CC fp2)
: fn<II>{fp1}
, fn<CC>{fp2}
{}
using fn<II>::operator();
using fn<CC>::operator();
};
int main()
{
fn_2 f(static_cast<II>(foo),
static_cast<CC>(foo));
std::cout << f(42) << std::endl;
std::cout << f('a') << std::endl;
}
Nothing fancy, but I am using enable_if to help compiler choose the correct version of operator() based upon the arity types of the stored function.
This is a GCC bug. Note that GCC always calls the fn<II> version, even if called with a parameter of type char. There is no way a compiler can tell which function template to call, because they have the exact same signature, and GCC is just picking one arbitrarily.
The code would work perfectly fine if char and int were independent types with no implicit conversions. However, since char and int can be implicitly converted between each other (yes, int to char can convert implicitly!), there may be an ambiguity in the call. GCC does the intuitive exception in selecting the call requiring no conversion at all, if present.
EDIT: I've been pointed out there is a templated argument that gets its own operator() function in here. This is something I definitely did not see.

Clang error "attempted to construct a reference element in a tuple with an rvalue" not given by gcc

I've written the following (relatively) simple implementation of a std::tuple zip function (analogous to Python's zip) with perfect forwarding:
template <size_t I, size_t N>
struct tuple_zip_helper {
template <typename... Tuples>
constexpr auto operator()(Tuples&&... tuples) const {
return tuple_cat(
make_tuple( forward_as_tuple(get<I>(forward<Tuples>(tuples))...) ),
tuple_zip_helper<I+1, N>()(forward<Tuples>(tuples)...)
);
}
};
template <size_t N>
struct tuple_zip_helper<N, N> {
template <typename... Tuples>
constexpr auto operator()(Tuples&&...) const {
return forward_as_tuple();
}
};
namespace std {
// Extend min to handle single argument case, for generality
template <typename T>
constexpr decltype(auto) min(T&& val) { return forward<T>(val); }
}
template <typename... Tuples>
auto tuple_zip(Tuples&&... tuples) {
static constexpr size_t min_size = min(tuple_size<decay_t<Tuples>>::value...);
return tuple_zip_helper<0, min_size>()( forward<Tuples>(tuples)... );
}
This appears to work fine for two or more tuples, even when mixing lvalues and rvalues and even when I use a BlabberMouth class to check for spurious copies and moves:
template <typename Tuple>
void f(Tuple&& tup) {
cout << get<0>(get<0>(tup)).data << endl;
}
struct Blabbermouth {
Blabbermouth(string const& str) : data(str) { }
Blabbermouth(Blabbermouth const& other) : data(other.data) { cout << data << " copied" << endl; }
Blabbermouth(Blabbermouth&& other) : data(move(other.data)) { cout << data << " moved" << endl; }
string data;
};
int main(int argc, char** argv) {
Blabbermouth x("hello ");
// prints "hello"
f(tuple_zip(
forward_as_tuple(x, 2),
forward_as_tuple(Blabbermouth("world"), 3)
));
}
It also works fine when I give it just one tuple without mixing lvalues and rvalues (clang-3.9, earlier versions of clang choke on this as well):
f(tuple_zip( forward_as_tuple(Blabbermouth("world"), 3) )); // prints "world"
However, when I mix lvalues and rvalues and only give one tuple, clang freaks out about something in a noexecpt specification (but gcc is fine, and even runs correctly):
auto x = BlabberMouth("hello");
f(tuple_zip( forward_as_tuple(x, 3) )); // clang freaks out, gcc okay
Live Demo
What (if anything) am I doing wrong? Should gcc be complaining, or should clang not be complaining? Does my code have any dangling references that I'm just "getting lucky" with, and that's why clang is objecting? Should I have done this differently? If clang is the one wrong here, can anyone suggest a workaround? (And/or link me to a bug report?)
Update
#Oktalist contributed a much more minimal example that illustrates the same problem:
struct foo {};
int main(int argc, char** argv)
{
foo f;
std::tuple<foo&> t(f);
std::tuple_cat(std::make_tuple(t), std::make_tuple());
}
(I had considered making my example more minimal as well, but I wasn't sure if what I was doing was exactly analogous to this, mainly because I don't fully understand how perfect forwarding interacts with auto/decltype(auto) return values, return value optimization (RVO), std::get and std::make_tuple, so I wanted to be sure I wasn't doing something else stupid.)
The bug is caused by the calls to tuple_cat (though not exactly in it; it seems to be some messiness inside libc++'s tuple's byzantine maze of constructors and SFINAE conditions), so the workaround is to avoid using it.
There is no point in doing recursive tuple_cats anyway; one pack expansion (or two) will do.
template<size_t I, typename... Tuples>
constexpr auto tuple_zip_one(Tuples&&... tuples) {
return forward_as_tuple(get<I>(forward<Tuples>(tuples))...);
}
template<size_t...Is, typename... Tuples>
constexpr auto tuple_zip_helper(index_sequence<Is...>, Tuples&&... tuples) {
return make_tuple(tuple_zip_one<Is>(forward<Tuples>(tuples)...)...);
}
template <typename... Tuples>
auto tuple_zip(Tuples&&... tuples) {
static constexpr size_t min_size = min({tuple_size<decay_t<Tuples>>::value...});
return tuple_zip_helper( make_index_sequence<min_size>(), forward<Tuples>(tuples)... );
}
I took the liberty of removing your UB-inducing min overload and simply using the standard initializer_list version instead.
Demo.

GCC 4.9 ambiguous overload template specialization

I'm running into an issue with gcc 4.9.2 (with -std=c++11) not compiling a piece of code with the error message being
call of overloaded 'InsertDataIntoInputMap(int&, boost::shared_ptr&)' is ambiguous
The code does compile with msvc 2013
#include <iostream>
#include <map>
#include <boost/shared_ptr.hpp>
struct Proxy
{
typedef std::map<int, int> InputDataMap;
int a;
};
template<class C, class D>
void InsertDataIntoInputMap(
const typename C::InputDataMap::key_type& key,
const D val)
{
std::cout << "Not shared\n";
}
template<class C, class D>
void InsertDataIntoInputMap(
const typename C::InputDataMap::key_type& key,
const boost::shared_ptr<D> val)
{
if (val)
{
std::cout << "Shared\n";
}
}
int main() {
int a;
boost::shared_ptr<double> x(new double(4.5));
InsertDataIntoInputMap<Proxy>(a, x);
}
while the following does actually compile with both gcc and msvc:
#include <iostream>
#include <boost/shared_ptr.hpp>
template<class C, class D>
void InsertDataIntoInputMap(
const C& key,
const D val)
{
std::cout << "Not shared\n";
}
template<class C, class D>
void InsertDataIntoInputMap(
const C& key,
const boost::shared_ptr<D> val)
{
if (val)
{
std::cout << "Shared\n";
}
}
int main() {
int a = 0;
boost::shared_ptr<double> x(new double(4.5));
InsertDataIntoInputMap<int>(a, x);
return 0;
}
I would have thought that the compiler should take the function with the boost::shared_ptr argument in both cases?
This problem can be reduced to an imprecision in partial ordering: Pairs in which no template-parameters appear that are involved in deduction are still considered and compaired. That issue was addressed by CWG #455 and #885 as well.
In your example, overload resolution isn't able to distinguish the overloads. Hence partial ordering is necessary. And partial ordering will try to perform deduction twice, with the parameter type P being typename C::InputDataMap::key_type.
However, that deduction is doomed to fail, since C solely appears in a non-deduced context. I.e. the type from both templates (for that particular pair) is not at least as specialized as the type from the respective other template - and that, in turn, implies that neither of the templates is more specialized than the other.
As noted by #T.C., the resolution of CWG #1391 helps. This part in particular:
Change 14.8.2.4 [temp.deduct.partial] paragraph 4 as follows:
Each type nominated above from the parameter template and the corresponding type from the argument template are used as the types of P and A. If a particular P contains no template-parameters that participate in template argument deduction, that P is not used to determine the ordering.
Now, the first parameter pair is entirely ignored in both ways (as the types of C are solely determined from the explicit argument list), and the second overload is found to be more specialized.
A simple alias can make that code work:
#include <iostream>
#include <map>
#include <boost/shared_ptr.hpp>
struct Proxy
{
typedef std::map<int, int> InputDataMap;
int a;
};
template<class C, class D, class F = typename C::InputDataMap::key_type>
void InsertDataIntoInputMap(
const F& key,
const D val)
{
std::cout << "Not shared\n";
}
template<class C, class D, class F = typename C::InputDataMap::key_type>
void InsertDataIntoInputMap(
const F& key,
const boost::shared_ptr<D> val)
{
if (val)
{
std::cout << "Shared\n";
}
}
int main() {
int a;
boost::shared_ptr<double> x(new double(4.5));
InsertDataIntoInputMap<Proxy>(a, x);
}
But imo. this shouldn't work, cause I thought, the draft says, the compiler will not consider the C::InputDataMap - Namespace in
class F = typename C::InputDataMap::key_type
and F will be a non-deduced context (like key_type).

Chained invocation of C++11 std::bind doesn't work

I have a problem when invoking nested std::bind expressions. The following code demonstrates the problem. It fails to compile with libc++, but works with boost:
#define BOOST 0
#if BOOST
#include <boost/function.hpp>
#include <boost/bind.hpp>
using boost::function;
using boost::bind;
#else
#include <functional>
using std::function;
using std::bind;
using std::placeholders::_1;
#endif
int sum(int a, int b) { return a+b; }
// works
template <typename F>
int yeah(F f, int c)
{
return f(c);
}
// breaks with libc++
template <typename F>
int nope(F f, int c)
{
return bind(f, c)();
}
// fixes the problem
template <typename F>
int fix1(F f, int c)
{
function<int(int)> g = f;
return bind(g, c)();
}
template <typename F>
class protect_t
{
public:
typedef typename F::result_type result_type;
explicit protect_t(F f): f_(f) {}
template <typename... Args>
result_type operator()(Args&&... args)
{
return f_(std::forward<Args>(args)...);
}
private:
F f_;
};
template <typename F>
protect_t<F> protect(F f)
{
return protect_t<F>(f);
}
// compilation fails with libc++
template <typename F>
int fix2(F f, int c)
{
return bind(protect(f), c)();
// F copy(f); // fails due to this!
}
#include <iostream>
int main()
{
std::cout << yeah(bind(sum, _1, 4), 5) << std::endl; // works
std::cout << nope(bind(sum, _1, 4), 5) << std::endl; // breaks
std::cout << fix1(bind(sum, _1, 4), 5) << std::endl; // fixes
std::cout << fix2(bind(sum, _1, 4), 5) << std::endl; // doesn't compile
}
Wrapping the bind expression in a std::function (see fix1) remedies the problem, albeit by sacrificing speed due to run-time polymorphism disabling inlining (haven't measured it though).
Wrapping the bind expression in protect_t (see fix2) is inspired by boost::protect, however, compilation with libc++ fails due to bind expressions not being copyable. Which makes me wonder why wrapping them in std::function works anyway.
Any idea how to solve this problem? What's wring with std::bind anyway? First I thought the problem is related to eager evaluation of bind expressions dictated by the C++11 standard (see here), but that would not be a problem here, would it?
The standard says that any callable can be wrapped using std::bind, including those produced by a preceding call to std::bind. Your problem is caused by a deficiency in the implementation of the standard library you're using, the solution is either to upgrade or, if this bug isn't still fixed, to switch to a different implementation.