Ambiguous deduction in SFINAE template constructor in clang++, not g++ - c++

The following example:
#include <iostream>
template<typename T>
struct X {
static constexpr bool B = std::is_same_v<T, int>;
template <bool Z = B, std::enable_if_t<Z, int> = 0>
X(T t) { std::cout << t << " - int\n"; }
template <bool Z = B, std::enable_if_t<!Z, int> = 0>
X(T t) { std::cout << t << " - not int\n"; }
};
int main()
{
X x(5);
X y(5.0);
}
Results in an ambiguous deduction error when compiled using clang++ (I tried up to 11.0) with -std=c++1z. Compilation terminates successfully with g++ 9.3.0.
Who is right? Why? Is there a bug associated with this?

Related

Template conversion operator in template class - to function pointer

I'm trying to make my class be convertible to a function pointer, for a slew of reasons unrelated to this post.
When I try to do this with a non-template class, it works fine. Below, Bar bar; bar(1) correctly compiles, and segfaults as-expected. But Foo<int>; foo(1) doesn't compile at all.
I've tried multiple compilers, and I get: mismatched types 'Args' and 'int'
Any ideas? Live demo: https://wandbox.org/permlink/alSGBssfSd4pHgdl
#include <iostream>
#include <tuple>
using namespace std;
template<typename... Args>
using Test = void(*)(Args...);
template<typename T>
struct Foo {
template<typename... Args>
operator Test<Args...>() {
return Test<Args...>{};
}
};
struct Bar {
template<typename... Args>
operator Test<Args...>() {
return Test<Args...>{};
}
};
int main()
{
Foo<int> foo;
// foo(1);
Bar bar;
bar(1);
return 0;
}
Tried this awful syntax, too:
template<typename... Args>
(*operator void() const)(Args...) {
return {};
}
You can try this:
#include <iostream>
#include <tuple>
using namespace std;
template<typename... Args>
using Test = void(*)(Args...);
template<typename T>
struct Foo {
template<typename... Args>
operator Test<Args...>()
{
std::cout << __FUNCTION__ << std::endl;
return Test<Args...>{};
}
};
struct Bar {
template<typename... Args>
operator Test<Args...>()
{
std::cout << __FUNCTION__ << std::endl;
return Test<Args...>{};
}
};
int main()
{
Foo<int> foo;
auto x = static_cast<Test<int, double>>(foo);
Bar bar;
auto y = static_cast<Test<char, float>>(bar);
return 0;
}
When using Visual C++ 2019, I get the following run-time output:
Foo<int>::operator void (__cdecl *)(int,double)
Bar::operator void (__cdecl *)(char,float)
The use of the static_cast is to force the usage of the overloaded operator member functions.
Alternatively, you can also try:
#include <iostream>
#include <tuple>
#include <type_traits>
using namespace std;
template<typename... Args>
using Test = void(*)(Args...);
template<typename T>
struct Foo {
template<typename... Args>
Test<Args...> operator()(int x)
{
return Test<Args...>{};
}
};
struct Bar {
template<typename... Args>
Test<Args...> operator()(int x)
{
return Test<Args...>{};
}
};
int main()
{
Foo<int> foo;
auto w = foo.template operator()<int, double>(1);
std::cout << "w: " << typeid(w).name() << std::endl;
auto x = foo(2);
std::cout << "x: " << typeid(x).name() << std::endl;
Bar bar;
auto y = bar.template operator()<char, float>(3);
std::cout << "y: " << typeid(y).name() << std::endl;
auto z = bar(4);
std::cout << "z: " << typeid(z).name() << std::endl;
return 0;
}
When using Visual C++ 2019, I get the following run-time output:
w: void (__cdecl*)(int,double)
x: void (__cdecl*)(void)
y: void (__cdecl*)(char,float)
z: void (__cdecl*)(void)
In this way, the object is now callable and returns a function pointer.

template instantiation with multiple template inheritance

What are the rules for template instantiation when we pass a (multi)derived class to a template function expecting base class? For example:
#include <iostream>
template <int x>
struct C {};
struct D : C<0>, C<1> {};
template <int x>
void f (const C<x> &y) { std::cout << x << "\n"; }
int main ()
{
f (D ());
}
MSVC 2015 prints 0, clang 3.8 - 1 and gcc 6.2 gives compiler error (Demo). And even if you SFINAE-away all overloads except one, the result will still be different:
#include <iostream>
template <int x> struct C {};
template<>
struct C<0> { using type = void; };
struct D : C<0>, C<1> {};
template <int x, typename = typename C<x>::type>
void f (const C<x> &y) { std::cout << x << "\n"; }
int main ()
{
f (D ());
}
Now it compiles only with MSVC, and if you swap C<0> and C<1> only clang will compile it. The problem is that MSVC only tries to instantiate first base, clang - last and gcc prints error too early. Which compiler is right?
gcc 5.4:
/tmp/gcc-explorer-compiler11685-58-1h67lnf/example.cpp: In function 'int main()':
13 : error: no matching function for call to 'f(D)'
f (D ());
^
9 : note: candidate: template<int x> void f(const C<x>&)
void f (const C<x> &y) { std::cout << x << "\n"; }
^
9 : note: template argument deduction/substitution failed:
13 : note: 'const C<x>' is an ambiguous base class of 'D'
f (D ());
^
Compilation failed
Which seems to me to be the correct result, since C<0> and C<1> are equally specialised.
Same result for gcc 6.2
clang 3.8.1 compiles it, which in my view is a compiler bug.
update:
I don't know the actual use case but I was wonder whether this might work for you:
#include <utility>
#include <iostream>
template<class T>
struct has_type
{
template<class U> static auto test(U*) -> decltype(typename U::type{}, std::true_type());
static auto test(...) -> decltype(std::false_type());
using type = decltype(test((T*)0));
static const auto value = type::value;
};
template <int x> struct C {};
template<>
struct C<0> { using type = int; };
template<int...xs>
struct enumerates_C : C<xs>...
{
};
struct D : enumerates_C<0, 1> {};
template<int x, std::enable_if_t<has_type<C<x>>::value>* = nullptr>
void f_impl(const C<x>& y)
{
std::cout << x << "\n";
}
template<int x, std::enable_if_t<not has_type<C<x>>::value>* = nullptr>
void f_impl(const C<x>& y)
{
// do nothing
}
template <int...xs>
void f (const enumerates_C<xs...> &y)
{
using expand = int[];
void(expand { 0,
(f_impl(static_cast<C<xs> const &>(y)),0)...
});
}
int main ()
{
f (D ());
}
expected output (tested on apple clang):
0

Variadic template using lambdas : error with g++ but running with clang++

While playing with variadic templates, classes, functions and lambdas, (from here) I found that following code is running with clang++ while not running with g++ :
#include <iostream>
#include <string>
using namespace std;
template <class... F>
struct overload_set : F...
{
overload_set(F... f) : F(f)... {}
};
template <class... F>
auto overload(F... f)
{
return overload_set<F...>(f...);
}
int main()
{
auto func = overload (
[](int &val) { val *= 2; },
[](string &arg) { arg += arg; },
[](char &c) { c = 'x'; }
);
int val = 10;
string str = "stackoverflow";
char ch = 's';
cout << val << " : " << str << " : " << ch << endl;
func(val);
func(str);
func(ch);
cout << val << " : " << str << " : " << ch << endl;
return 0;
}
For clang : coliru
For g++ : coliru
g++ is giving ambiguous operator() for func(val), func(str) and func(c). I think the operator() must not be ambiguous, as each one is having different arguments.
What's the problem with g++?
This has little to do with lambdas, variadic templates, operators or any advanced C++1{xy} stuff. Let's simplify:
struct foo
{
void func(int&){}
};
struct bar
{
void func(char&){}
};
struct test : foo, bar {};
int main()
{
test t;
int i = 1;
char c = 'a';
t.func(i);
t.func(c);
}
This fails to compile in either g++ or clang++. Which is a good thing too, because that's how the language is specified to work.
If we change func to operator(), g++ continues to reject the program but clang++ either accepts or rejects it, depending on how the operator is called:
t.operator()(c); // rejected
t(c); // accepted
Which looks like a clang bug to me.
In order to make the code above compile, a very small change is needed:
struct test : foo, bar {
using foo::func;
using bar::func;
};
Now I have no idea how to make pack expansion work in the using directive, or if it's indeed possible. But there's a workaround:
template <class... F> struct overload_set;
template <> struct overload_set<> {};
template <class F> struct overload_set<F> : F {
using F::operator();
overload_set(F f) : F(f) {}
};
template <class F, class... Fs>
struct overload_set<F, Fs...> : F, overload_set<Fs...>
{
overload_set(F f, Fs... fs) : F(f), overload_set<Fs...>(fs...) {}
using F::operator();
using overload_set<Fs...>::operator();
};
With this change your code compiles with both g++ and clang++.

How to make sure std::tuple use c++11 move semantics in the following code

I have written a function to apply a function to a std::tuple as below (based on "unpacking" a tuple to call a matching function pointer).
I am concerned that the tuples might be copied around. I have a very basic idea of what move semantics does, and understand concepts like && and rvalue in the string examples commonly found. But I don't know much about how std::forward() and the likes work. And I am not sure how to handle it when there is also packing and variadic programming. (I added a few std::forward and &&'s around and soon get compilation errors.)
Can someone please explain how to make move semantics work for the tuples here? One additional question is, how can I verify (except for visual inspection of code) that move semantic indeed works for the tuples in the code?
Thanks in advance.
#include <tuple>
#include <iostream>
#include <functional>
template<int ...> struct seq {};
template<int N, int ...S> struct gens : gens<N-1, N-1, S...> {};
template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; };
template <typename R, typename Tp, typename ...FArgs>
struct t_app_aux {
template<int ...S>
R static callFunc(std::function<R (FArgs...)> f,Tp t,seq<S...>) {
return f(std::get<S>(t) ...);
}
};
template <typename R, typename Tp, typename ...FArgs>
R t_app(std::function<R (FArgs...)> f, Tp t) {
static_assert(std::tuple_size<Tp>::value == sizeof...(FArgs), "type error: t_app wrong arity");
return t_app_aux<R, Tp, FArgs...>::callFunc(f,t,typename gens<sizeof...(FArgs)>::type());
}
int main(void)
{
std::tuple<int, float, double> t = std::make_tuple(1, 1.2, 5);
std::function<double (int,float,double)> foo1 = [](int x, float y, double z) {
return x + y + z;
};
std::cout << t_app(foo1,t) << std::endl;
}
There are copies with your current implementation: http://ideone.com/cAlorb
I added a type with some log:
struct foo
{
foo() : _value(0) { std::cout << "default foo" << std::endl; }
foo(int value) : _value(value) { std::cout << "int foo" << std::endl; }
foo(const foo& other) : _value(other._value) { std::cout << "copy foo" << std::endl; }
foo(foo&& other) : _value(other._value) { std::cout << "move foo" << std::endl; }
int _value;
};
And also before/after your application:
std::cout << "Function created" << std::endl;
std::cout << t_app(foo1,t) << std::endl;
std::cout << "Function applied" << std::endl;
It gives:
Function created
copy foo
copy foo
7.2
Function applied
So then, to fix this adding forward is done like this:
template <typename R, typename Tp, typename ...FArgs>
struct t_app_aux {
template<int ...S>
R static callFunc(std::function<R (FArgs...)> f, Tp&& t, seq<S...>) {
return f(std::get<S>(std::forward<Tp>(t)) ...);
}
};
template <typename R, typename Tp, typename ...FArgs>
R t_app(std::function<R (FArgs...)> f, Tp&& t)
{
static_assert(std::tuple_size<typename std::remove_reference<Tp>::type>::value == sizeof...(FArgs),
"type error: t_app wrong arity");
return t_app_aux<R, Tp, FArgs...>::callFunc(f, std::forward<Tp>(t), typename gens<sizeof...(FArgs)>::type());
}
As you can see it removes unwanted copies: http://ideone.com/S3wF6x
Function created
7.2
Function applied
The only problem was to handle the static_assert because std::tuple_size was called on a std::tuple<>& and it did not work. I used typename std::remove_reference<Tp>::type but maybe there is a clever and more universal way ?

GCC ICE -- alternative function syntax, variadic templates and tuples

(Related to C++0x, How do I expand a tuple into variadic template function arguments?.)
The following code (see below) is taken from this discussion. The objective is to apply a function to a tuple. I simplified the template parameters and modified the code to allow for a return value of generic type.
While the original code compiles fine, when I try to compile the modified code with GCC 4.4.3,
g++ -std=c++0x main.cc -o main
GCC reports an internal compiler error (ICE) with the following message:
main.cc: In function ‘int main()’:
main.cc:53: internal compiler error: in tsubst_copy, at cp/pt.c:10077
Please submit a full bug report,
with preprocessed source if appropriate.
See <file:///usr/share/doc/gcc-4.4/README.Bugs> for instructions.
Question: Is the code correct? or is the ICE triggered by illegal code?
// file: main.cc
#include <tuple>
// Recursive case
template<unsigned int N>
struct Apply_aux
{
template<typename F, typename T, typename... X>
static auto apply(F f, const T& t, X... x)
-> decltype(Apply_aux<N-1>::apply(f, t, std::get<N-1>(t), x...))
{
return Apply_aux<N-1>::apply(f, t, std::get<N-1>(t), x...);
}
};
// Terminal case
template<>
struct Apply_aux<0>
{
template<typename F, typename T, typename... X>
static auto apply(F f, const T&, X... x) -> decltype(f(x...))
{
return f(x...);
}
};
// Actual apply function
template<typename F, typename T>
auto apply(F f, const T& t)
-> decltype(Apply_aux<std::tuple_size<T>::value>::apply(f, t))
{
return Apply_aux<std::tuple_size<T>::value>::apply(f, t);
}
// Testing
#include <string>
#include <iostream>
int f(int p1, double p2, std::string p3)
{
std::cout << "int=" << p1 << ", double=" << p2 << ", string=" << p3 << std::endl;
return 1;
}
int g(int p1, std::string p2)
{
std::cout << "int=" << p1 << ", string=" << p2 << std::endl;
return 2;
}
int main()
{
std::tuple<int, double, char const*> tup(1, 2.0, "xxx");
std::cout << apply(f, tup) << std::endl;
std::cout << apply(g, std::make_tuple(4, "yyy")) << std::endl;
}
Remark: If I hardcode the return type in the recursive case (see code), then everything is fine. That is, substituting this snippet for the recursive case does not trigger the ICE:
// Recursive case (hardcoded return type)
template<unsigned int N>
struct Apply_aux
{
template<typename F, typename T, typename... X>
static int apply(F f, const T& t, X... x)
{
return Apply_aux<N-1>::apply(f, t, std::get<N-1>(t), x...);
}
};
Alas, this is an incomplete solution to the original problem.
I tried you code on g++4.6. It does not compile due to missing implementation. However, one way to achieve generality would be to wrap the free standing function in a std::function wrapper and use result_type typedef like below.
template<typename F, typename T>
typename F::result_type apply(F f, const T& t)
{
...
}
int f(int p1, double p2, std::string p3)
{
std::cout << "int=" << p1 << ", double=" << p2 << ", string=" << p3 << std::endl;
return 1;
}
int main()
{
std::tuple<int, double, char const*> tup(1, 2.0, "xxx");
std::function<int (int, double, char const *)> func = &f;
std::cout << apply(func, tup) << std::endl;
}