Unexpected SFINAE failure using std::result_of - c++

In c++14, std::result_of is supposed to result in SFINAE if the expression is ill-formed*. Instead I'm getting a compilation error ("invalid operands to binary expression") on my final case below (i.e. letting the compiler deduce type for std::plus<>). The first three cases work as expected. Code and results shown below.
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/apply.hpp>
#include <iostream>
#include <utility>
#include <stdexcept>
#include <functional>
namespace mpl = boost::mpl;
template <typename OP, typename T, typename OP_T = typename mpl::apply<OP, T>::type>
struct apply_if_ok: OP_T {
template <typename...Args, typename R = std::result_of_t<OP_T(Args...)>>
R operator()(Args&&...args) const {
return static_cast<OP_T>(*this)(std::forward<Args>(args)...);
}
template <typename...Args>
auto operator()(...) const {
// throw std::runtime_error("Invalid arguments");
return "Invalid arguments";
}
};
int main() {
using OP = std::plus<mpl::_>;
int i = 3;
auto n1 = apply_if_ok<OP, void>()(1, 2);
std::cout << "plus (1, 2) = " << n1 << std::endl;
auto n2 = apply_if_ok<OP, void>()(1, &i);
std::cout << "plus (1, *) = " << n2 << std::endl;
auto n3 = apply_if_ok<OP, int>()(&i, &i);
std::cout << "plus (*, *) = " << n3 << std::endl;
// auto n4 = apply_if_ok<OP, void>()(&i, &i);
// std::cout << "plus (*, *) = " << n4 << std::endl;
}
The output:
% c++ -std=c++1y -g -pedantic sfinae_result_of.cc -o sfinae_result_of
./sfinae_result_of
plus (1, 2) = 3
plus (1, *) = 0x7fff5e782a80
plus (*, *) = Invalid arguments
% c++ -v
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.1.0
Thread model: posix
Any pointers on what I'm doing wrong would be appreciated!
Thanks.
From cppreference.com. I think relevant standard reference is 20.10.7.6, comments on last table entry.

This is caused by a bug in libc++, which I actually just reported a few days ago. (Update: The bug has been fixed in trunk.)
The problem is that their "diamond functor" implementation is non-conforming. For instance, they implemented std::plus<void>::operator() as follows:
template <class _T1, class _T2>
_LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY
auto operator()(_T1&& __t, _T2&& __u) const
{ return _VSTD::forward<_T1>(__t) + _VSTD::forward<_T2>(__u); }
when it should be
template <class _T1, class _T2>
_LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY
auto operator()(_T1&& __t, _T2&& __u) const
-> decltype(_VSTD::forward<_T1>(__t) + _VSTD::forward<_T2>(__u))
{ return _VSTD::forward<_T1>(__t) + _VSTD::forward<_T2>(__u); }
The missing trailing-return-type means two things:
They are no longer "perfectly returning"; instead, the return type is deduced using the rules for auto, essentially causing it to be decayed. The trailing return type, when the expression in it is well-formed, is equivalent to returning decltype(auto).
SFINAE no longer applies to the expression _VSTD::forward<_T1>(__t) + _VSTD::forward<_T2>(__u). In a bug-free implementation, the operator() declaration would be removed from the overload set, overload resolution will fail, and std::result_of will then do its SFINAE-friendly magic. Instead, the function declaration is successfully instantiated, selected by overload resolution, and then a hard error occurs when the compiler attempts to instantiate the body to actually deduce the return type.
Your problem is caused by #2.

Related

using declaration: one more bug of gcc and clang?

Why do gcc HEAD 10.0.0 20190 and Clang HEAD 9.0.0 both reject this program?
#include <iostream>
void g( int x )
{
std::cout << "Hello g( " << x << " )\n";
}
template <int N>
void g()
{
std::cout << "Hello g<N>( " << N << " )\n";
}
namespace N
{
using ::g;
}
void g( int x = 20 );
template <int N = 10>
void g();
int main()
{
N::g();
N::g<>();
}
For example gcc issues the error
prog.cc: In function 'int main()':
prog.cc:27:11: error: no matching function for call to 'g()'
27 | N::g<>();
| ^
prog.cc:9:6: note: candidate: 'template<int N> void g()'
9 | void g()
| ^
prog.cc:9:6: note: template argument deduction/substitution failed:
prog.cc:27:11: note: couldn't deduce template parameter 'N'
27 | N::g<>();
| ^
though according to the C++ 20 (and 17) Standard (9.8 The using declaration)
11 [Note: For a using-declaration whose nested-name-specifier names a
namespace, members added to the namespace after the using-declaration
are not in the set of introduced declarations, so they are not
considered when a use of the name is made. Thus, additional overloads
added after the using-declaration are ignored, but default function
arguments (9.2.3.6), default template arguments (13.1), and template
specializations (13.6.5, 13.8.3) are considered. — end note]
Based on my reading of the standard, I believe this is a bug.
This issue is the subject of Core issue 1907. The current direction is to treat such cases as ill-formed, no diagnostic required.
As it turns out, some implementations track default arguments on a "per-entity" basis (so it would be difficult to not consider default arguments added in a later redeclaration), while others track them on a "per-declaration" basis (so it would difficult to make them consider such default arguments). CWG decided to accommodate both implementation strategies by classifying code that depends on such things IFNDR.
I think the problem is that you're re-declaring the g<int> template function after implicitly declaring it during its definition.
This minimised example also fails to compile. Note no namespaces involved:
#include <iostream>
template <int N>
void g()
{
std::cout << "Hello g<N>( " << N << " )\n";
}
// redeclaration
template <int N = 10>
void g();
int main()
{
g<>();
}
whereas this compiles:
#include <iostream>
// declaration
template <int N = 10>
void g();
// definition
template <int N>
void g()
{
std::cout << "Hello g<N>( " << N << " )\n";
}
int main()
{
g<>();
}

Variadic function wont compile with clang

First off, I apologize if this is a duplicate, I will be happy to take it down but I am not even sure what the issue/diagnosis is here.
Anyway, my code here works with gcc and not clang - why is this the case? I am clearly not able to understand why clang cant compile this.
#include <iostream>
#include <type_traits>
using std::cout;
using std::endl;
template <typename T, typename... Args, typename std::enable_if<!sizeof...(Args)>::type* = nullptr>
void func(int start_size, int idx)
{
cout << start_size << " " << idx << endl;
return;
}
template <typename T, typename... Args, typename std::enable_if<sizeof...(Args)>::type* = nullptr>
void func(int start_size, int idx)
{
if((idx + 1) == int(start_size - int(sizeof...(Args))))
{
cout << start_size << " " << idx << endl;
return;
}
func<Args...>(start_size, idx);
}
template <typename... Args>
void func_wrapper(int idx)
{
func<Args...>(sizeof...(Args),idx);
}
int main()
{
func_wrapper<int,double,char>(1);
}
Error:
prog.cc:37:5: error: no matching function for call to 'func'
func<Args...>(sizeof...(Args),idx);
^~~~~~~~~~~~~
prog.cc:44:5: note: in instantiation of function template specialization 'func_wrapper<int, double, char>' requested here
func_wrapper<int,double,char>(1);
^
prog.cc:16:6: note: candidate template ignored: requirement '!sizeof...(Args)' was not satisfied [with T = int, Args = <double, char>]
void func(int start_size, int idx)
^
prog.cc:23:6: note: candidate template ignored: substitution failure [with T = int, Args = <double, char>]: non-type template argument evaluates to 2, which cannot be narrowed to type 'bool'
void func(int start_size, int idx)
^
1 error generated.
Wandbox: https://wandbox.org/permlink/yqki47uYcwUlE013
clang is correct in rejecting this code. To eliminate the error, you should explicitly apply a conversion:
std::enable_if<bool(sizeof...(Args))>
The reasoning is:
[temp.arg.nontype]/5
The following conversions are performed on each expression used as a
non-type template-argument. If a non-type template-argument cannot be
converted to the type of the corresponding template-parameter then the
program is ill-formed.
(5.1) For a non-type template-parameter of integral or enumeration
type, conversions permitted in a converted constant expression
([expr.const]) are applied.
Then [expr.const]/3 says that a narrowing conversion is not considered automatically:
A converted constant expression of type T is a literal constant
expression, implicitly converted to type T, where the implicit
conversion (if any) is permitted in a literal constant expression and
the implicit conversion sequence contains only user-defined
conversions, lvalue-to-rvalue conversions ([conv.lval]), integral
promotions ([conv.prom]), and integral conversions ([conv.integral])
other than narrowing conversions ([dcl.init.list])
Thus for this case, a narrowing conversion from std::size_t to bool, it should be explicit: bool(sizeof...(Args))
In addition of the missing explicit conversion from std::size_t to bool which would require code as
std::enable_if<sizeof...(Args) != 0>
There is an other error:
temp#res-8.3
The program is ill-formed, no diagnostic required, if:
[..]
every valid specialization of a variadic template requires an empty template parameter pack,
So
template <typename T,
typename... Args,
typename std::enable_if<sizeof...(Args) == 0>::type* = nullptr>
is invalid.
(There is also void* = nullptr which might be problematic).
You may write it with 2 overloads instead:
template <typename T>
void func(int start_size, int idx)
{
cout << start_size << " " << idx << endl;
}
template <typename T, typename T2, typename... Args> // Addition of T2, and change sizeof...
void func(int start_size, int idx)
{
if ((idx + 1) == int(start_size - int(1 + sizeof...(Args)))) {
cout << start_size << " " << idx << endl;
return;
}
func<T2, Args...>(start_size, idx);
}

use of boost::hana::eval_if_t before deduction of auto

A code snippet says more than a couple of paragraphs:
#include <boost/hana/fwd/eval_if.hpp>
#include <boost/hana/core/is_a.hpp>
#include <iostream>
#include <functional>
using namespace boost::hana;
template<class arg_t>
decltype(auto) f2(arg_t const& a)
{
constexpr bool b = is_a<std::reference_wrapper<std::string>,
arg_t>;
auto wrapper_case = [&a](auto _) -> std::string&
{ return _(a).get(); };
auto default_case = [&a]() -> arg_t const&
{ return a; };
return eval_if(b, wrapper_case, default_case);
}
int main()
{
int a = 3;
std::string str = "hi!";
auto str_ref = std::ref(str);
std::cout << f2(a) << ", " << f2(str) << ", " << f2(str_ref)
<< std::endl;
}
The compiler error is:
$> g++ -std=c++14 main.cpp
main.cpp: In instantiation of ‘decltype(auto) f2(const arg_t&) [with arg_t = int]’:
main.cpp:42:22: required from here
main.cpp:31:19: error: use of ‘constexpr decltype(auto) boost::hana::eval_if_t::operator()(Cond&&, Then&&, Else&&) const [with Cond = const bool&; Then = f2(const arg_t&) [with arg_t = int]::<lambda(auto:1)>&; Else = f2(const arg_t&) [with arg_t = int]::<lambda(auto:2)>&]’ before deduction of ‘auto’
return eval_if(b, wrapper_case, default_case);
~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There's no recursion, I use gcc-6.0.2 which presumably has solved some bugs about decltype(auto) and has a full working C++14 implementation, and also fits the boost::hana requirements, so, my error must be in my implementation but I don't know what is the error about.
NOTE: clang++ 3.8.0 throws a similar compiler error.
First, in case the path doesn't make it clear, boost/hana/fwd/eval_if.hpp is but a forward declaration. If you want to use it in earnest, you need to include the whole thing, i.e., boost/hana/eval_if.hpp. That's the cause of the original error.
Then, this bool is wrong:
constexpr bool b = is_a<std::reference_wrapper<std::string>,
arg_t>;
Coercing it to bool means that the type no longer carries the value information. Use auto.

g++ and clang++ different behaviour with SFINAE and SFINAE failure

A couple of questions for C++11 experts.
I'm fighting with SFINAE and I came across a strange case in which g++ (4.9.2), and clang++ (3.5.0) behave differently.
I have prepared the following sample code. I'm sorry but I'm unable to do it significantly more concise.
#include <string>
#include <iostream>
#include <typeinfo>
#include <type_traits>
template <typename X>
class foo
{
private:
template <typename R>
using enableIfIsInt
= typename std::enable_if<std::is_same<X, int>::value, R>::type;
public:
foo ()
{ }
template <typename R = void>
enableIfIsInt<R> bar ()
{ std::cout << "bar: is int\n"; }
void bar ()
{
std::cout << "bar: isn't int; is [" << typeid(X).name() << "]{"
<< typeid(enableIfIsInt<void>).name() << "}\n";
}
};
int main ()
{
foo<long> fl;
foo<int> fi;
fl.bar();
fi.bar();
return 0;
}
My idea was to create a template foo<X> class that (via SFINAE) can define a method in one or in another way depending on the X template argument.
The program compile well with g++ 4.9.2 but clang++ 3.5.0 give the following error
test.cpp:13:36: error: no type named 'type' in
'std::__1::enable_if<false, void>'; 'enable_if' cannot be used to disable
this declaration
= typename std::enable_if<std::is_same<X, int>::value, R>::type;
^~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:26:23: note: in instantiation of template type
alias 'enableIfIsInt' requested here
<< typeid(enableIfIsInt<void>).name() << "}\n";
^
test.cpp:36:7: note: in instantiation of member function
'foo<long>::bar' requested here
fl.bar();
^
1 error generated.
I suppose that is right clang++ but my first question to C++11 experts is: who right? g++ or clang++?
About the g++ produced program output, it's the following
bar: isn't int; is [i]{v}
so g++ seems to ignore the fl.bar(); instruction.
Now a little change: i modify the second version of foo<X>::bar() in this way
void bar ()
{ std::cout << "bar: isn't int; is [" << typeid(X).name() << "]\n"; }
deleting the std::enable_if inside the function abomination. Now both g++ and clang++ are compiling without problems and the output, for both compiled versions of the program, is
bar: isn't int; is [l]
bar: isn't int; is [i]
So, my second question is: what I'm doing wrong? Why, in the int case, I don't obtain the "is int" version of foo<X>::bar()?
Be patient with me if I'm doing some foolish: I'm trying to learn C++11.
And sorry for my bad English.
clang's error isn't coming from the substitution failure. It's coming from here:
void bar ()
{
std::cout << "bar: isn't int; is [" << typeid(X).name() << "]{"
<< typeid(enableIfIsInt<void>).name() << "}\n"; // <==
}
enableIfIsInt<void> isn't in the immediate context, that's a hard failure for X is not int. You simply can't use that expression in that context.
Once you remove that - the non-template bar() is always called. That's because both functions are equivalent matches and non-templates are preferred to templates in overload resolution.
So the real solution is to use tag-dispatching:
void bar() { bar(std::is_same<X, int>{}); }
void bar(std::true_type ) {
std::cout << "bar: is int\n";
}
void bar(std::false_type ) {
std::cout << "bar: isn't int; is [" << typeid(X).name() << "]\n";
}
with which both compilers happily yield:
bar: isn't int; is [l]
bar: is int

Call of overloaded template function is ambiguous

I have the following code.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
template <typename Type> inline Type max(Type t1, Type t2) {
return t1 > t2 ? t1 : t2;
}
template <typename Type> inline Type max(const std::vector<Type> &vec) {
return *std::max_element(vec.begin(),vec.end());
}
template <typename Type> inline Type max(const Type *parray, int size) {
return *std::max_element(parray,parray+size);
}
int main(int argc, char *argv[]) {
std::string sarray[] = {"we","were","her","pride","of","ten"};
std::vector<std::string> svec(sarray,sarray+6);
int iarray[] = {12,70,2,169,1,5,29};
std::vector<int> ivec(iarray,iarray+7);
float farray[] = {2.5,24.8,18.7,4.1,23.9};
std::vector<float> fvec(farray,farray+5);
int imax = max(max(ivec),max(iarray,7));
float fmax = max(max(fvec),max(farray,5));
std::string smax = max(max(svec),max(sarray,6));
std::cout << "imax should be 169 -- found: " << imax << '\n'
<< "fmax should be 24.8 -- found: " << fmax << '\n'
<< "smax should be were -- found: " << smax << '\n';
return 0;
}
I am attempting to implement two simple template functions to output the max element of a vector and an array. However, I am receiving the following error when the type is a string.
error: call of overloaded 'max(std::string, std::string)' is ambiguous
Why is this occuring, and what is the best way to remedy it?
The problem is that the compiler is finding multiple matching definitions of max via ADL and it doesn't know which to choose.
Try changing the call to max to use its qualified-id:
std::string smax = ::max(max(svec),max(sarray,6));
Your code
std::string smax = max(max(svec),max(sarray,6));
translates to:
std::string smax = max(string ,string );
After max(svec) and max(sarray,6) are evaluated using your templates. Now here the problem arises:
The standard library already comes with a templated max() function. The compiler will be unable to tell whether you want your version of max() or std::max().
Now you will ask why it worked for integers and floats. Answer is in this line you are specifically mentioning std::string. Hence the compiler is getting confused.
There can be work arounds. But since you need the best solution, I would say rename your max function say MAximum.
Why is this occuring?
The compiler error already tells you why. It does not know which version of max to use.
note: candidates are:
main.cpp:6:38: note: Type max(Type, Type) [with Type = std::basic_string]
...
/usr/include/c++/4.7/bits/stl_algobase.h:210:5: note: const _Tp& std::max(const _Tp&, const _Tp&) [with _Tp = std::basic_string]
Solution:
either explicitely call your max function or just call std::max (which already exists, so why would you want to reimplement it?).
Additionally, there is one ; too much after << "fmax should be 24.8 -- found: " << fmax << '\n'