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);
}
Related
Does anyone know why assigning type* = 0 doesn't work, while type* = nullptr does? In both cases typedef void type. Thanks
#include <type_traits>
#include <iostream>
template <class T,
typename std::enable_if<std::is_integral<T>::value>::type* = 0>
void do_stuff(T& t) {
std::cout << "do_stuff integral\n";
}
#if 0 // works
template <class T,
typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
void do_stuff(T& t) {
std::cout << "do_stuff integral\n";
}
#endif
struct S {};
int main(int argc, char *argv[])
{
int i = 1;
do_stuff(i);
return 0;
}
Compilation:
clang++ -pedantic -Wall -std=c++11 test190.cc && ./a.out
test190.cc:23:5: error: no matching function for call to 'do_stuff'
do_stuff(i);
^~~~~~~~
test190.cc:6:6: note: candidate template ignored: substitution failure
[with T = int]: null non-type template argument must be cast to template
parameter type 'typename
std::enable_if<std::is_integral<int>::value>::type *' (aka 'void *')
void do_stuff(T& t) {
^
1 error generated.
Technically speaking, this is because a non-type template argument must be a "converted constant expression" of the parameter type. This means that the argument itself must be a constant expression, and its conversion to the required parameter type must use only the conversions specified in [expr.const]/4.
According to [expr.const]/4, null pointer conversions are only allowed from std::nullptr_t. In other words, the conversion from 0 to a null pointer value is not allowed as part of the implicit conversion sequence in a converted constant expression.
Yet it's perfectly legitimate to specify static_cast<T*>(0) as a template argument to a non-type template parameter of type T*. In other words, a null pointer conversion from 0 is allowed as part of a constant expression. It's only when the conversion is done at a certain point---after computing the argument and while converting the argument type to the parameter type---that the standard forbids it.
I have no idea about the rationale for this rule.
** nullptr and 0 are not the same. **
For a very clear explanation please see the following:
https://hackernoon.com/what-exactly-is-nullptr-in-c-94d63y6t
#brian has provided a very good technical answer, but I felt it necessary to add this answer since we should no longer be trying to use 0 for pointer values.
struct A
{
template <typename T>
constexpr explicit operator
std::enable_if_t<
std::is_same<std::decay_t<T>, int>{},
int
>() const noexcept
{
return -1;
}
};
int main()
{
A a;
std::cout << int(a) << std::endl;
}
The error is clang-7.0.1:
<source>:21:16: error: no matching conversion for functional-style cast from 'A' to 'int'
std::cout << int(a) << std::endl;
^~~~~
<source>:7:22: note: candidate template ignored: couldn't infer template argument 'T'
constexpr explicit operator
^
That pattern just doesn't work for conversion functions. The problem is, in order to determine if a is convertible to int, we look for an operator int() - but what we get is:
std::enable_if_t<std::is_same<std::decay_t<T>, int>{}, int>
That's a non-deduced context - so we don't find int.
You have to move the condition into a defaulted parameter:
template <typename T, std::enable_if_t<std::is_same_v<T, int>, int> = 0>
constexpr explicit operator T() const noexcept { return -1; }
This way, we can deduce T and then let SFINAE do its magic. Note that you don't need decay since we don't have any kind of reference.
I wanted to implement a overload for operator<< that allowed me to call a given function and output the result.
I therefore wrote an overload, but the conversion to bool is selected and when writing a function myself, it would not compile.
EDIT: Know that I do not want to call the lambda,
but instead pass it to the function where it should be called with a default constructed parameter list.
I have appended my code:
#include <iostream>
template<typename T>
void test(T *) {
std::cout << "ptr" << std::endl;
}
template<typename T>
void test(bool) {
std::cout << "bool" << std::endl;
}
template<typename Ret, typename ...Args>
void test(Ret(*el)(Args...)) {
std::cout << "function ptr\n" << el(Args()...) << std::endl;
}
template<typename Char_T, typename Char_Traits, typename Ret, typename ...Args>
std::basic_ostream<Char_T, Char_Traits>& operator<<(
std::basic_ostream<Char_T, Char_Traits> &str, Ret(*el)(Args...)) {
return str << el(Args()...);
}
int main() {
std::boolalpha(std::cout);
std::cout << []{return 5;} << std::endl; // true is outputted
test([]{return 5;}); // will not compile
}
I use gcc 7.3.1 with the version flag -std=c++14.
EDIT: Error message:
main.cc: In function ‘int main()’:
main.cc:25:23: error: no matching function for call to ‘test(main()::<lambda()>)’
test([]{return 5;});
^
main.cc:5:6: note: candidate: template<class T> void test(T*)
void test(T *) {
^~~~
main.cc:5:6: note: template argument deduction/substitution failed:
main.cc:25:23: note: mismatched types ‘T*’ and ‘main()::<lambda()>’
test([]{return 5;});
^
main.cc:9:6: note: candidate: template<class T> void test(bool)
void test(bool) {
^~~~
main.cc:9:6: note: template argument deduction/substitution failed:
main.cc:25:23: note: couldn't deduce template parameter ‘T’
test([]{return 5;});
^
main.cc:13:6: note: candidate: template<class Ret, class ... Args> void test(Ret (*)(Args ...))
void test(Ret(*el)(Args...)) {
^~~~
main.cc:13:6: note: template argument deduction/substitution failed:
main.cc:25:23: note: mismatched types ‘Ret (*)(Args ...)’ and ‘main()::<lambda()>’
test([]{return 5;});
Your problem here is that Template Argument Deduction is only done on the actual argument passed to test. It's not done on all possible types that the argument could possibly converted to. That might be an infinite set, so that's clearly a no-go.
So, Template Argument Deduction is done on the actual lambda object, which has an unspeakable class type. So the deduction for test(T*) fails as the lambda object is not a pointer. T can't be deduced from test(bool), obviously. Finally, the deduction fails for test(Ret(*el)(Args...)) as the lambda object is not a pointer-to-function either.
There are a few options. You might not even need a template, you could accept a std::function<void(void)> and rely on the fact that it has a templated constructor. Or you could just take a test(T t) argument and call it as t(). T will now deduce to the actual lambda type. The most fancy solution is probably using std::invoke, and accepting a template vararg list.
Even though non-capturing lambdas have an implicit conversion to function pointers, function templates must match exactly for deduction to succeed, no conversions will be performed.
Therefore the easiest fix is to force the conversion with a +
int main() {
std::boolalpha(std::cout);
std::cout << []{return 5;} << std::endl; // true is outputted
test(+[]{return 5;});
// ^
}
template<typename T>
void test(bool) {
std::cout << "bool" << std::endl;
}
Template is not needed. In fact you overload functions, not templates. Replace it with
void test(bool) {
std::cout << "bool" << std::endl;
}
Now your sample will compile.
#include <iostream>
int main(){
int a = 1;
long long b = 2;
std::cout<<(a<b);
std::cout<<std::min(a, b);
return 0;
}
> In file included from /usr/include/c++/4.8/bits/char_traits.h:39:0,
> from /usr/include/c++/4.8/ios:40,
> from /usr/include/c++/4.8/ostream:38,
> from /usr/include/c++/4.8/iostream:39,
> from sum_to.cpp:1: /usr/include/c++/4.8/bits/stl_algobase.h:239:5: note: template<class
> _Tp, class _Compare> const _Tp& std::min(const _Tp&, const _Tp&, _Compare)
> min(const _Tp& __a, const _Tp& __b, _Compare __comp)
> ^ /usr/include/c++/4.8/bits/stl_algobase.h:239:5: note: template argument deduction/substitution failed: sum_to.cpp:7:29:
> note: deduced conflicting types for parameter ‘const _Tp’ (‘int’ and
> ‘long long int’)
> std::cout<<std::min(a, b);
---
Thanks to chris comment in function overloading post
Template argument deduction doesn't take conversions into account. One
template parameter can't match two types
So std::min fail.
Why < would work?
Because built-in < applies Numeric promotions, and template argument deduction doesn't.
As explained in other answers, the reason is that std::min requires the types of the arguments to be identical if deduction is to be performed, while < implies the usual arithmetic conversions (§5.9/2), which will make sure that the types are converted to a "common denominator". Note how §13.6/12 lists up built-in operators as candidates:
For every pair of promoted arithmetic types L and R, there exist
candidate operator functions of the form
// […]
LR operator<(L , R );
// […]
where LR is the result of the usual arithmetic conversions between
types L and R.
Actually, std::min should be able to deal with distinct types. The following is a more modern approach:
template <typename T>
constexpr decltype(auto) min(T&& t) {return std::forward<T>(t);}
template <typename T, typename U, typename... Args>
constexpr auto min(T&& t, U&&u, Args&&... args) {
std::common_type_t<T, U> const& _t(std::forward<T>(t)), _u(std::forward<U>(u));
return min(_t<_u? _t : _u, std::forward<Args>(args)...);
}
Demo.
It is because std::min is a template function.
template <class T> const T& min (const T& a, const T& b) {
return !(b<a)?a:b; // or: return !comp(b,a)?a:b; for version (2)
}
so it needs the arguments to have the same type, but if you use (a<b), so a could implicitly converted to a long long
The < operator is binary, so the compiler could convert arguments to the same type and compare them.
Otherwise min function should return something. How could compiler guess which type should he return?
Primitive types don't overload operators, so usual arithmetic conversions are applied and your int is converted to a long long, and the "<" has a valid meaning.
You can't even overload operators for primitive types:
https://isocpp.org/wiki/faq/intrinsic-types#intrinsics-and-operator-overloading
Example to show that your int is promoted to long long
// common_type example
#include <iostream>
#include <type_traits>
int main() {
typedef std::common_type<int, long long>::type A; // i
std::cout << "A: " << std::is_same<long long,A>::value << std::endl;
return 0;
}
Documentation
http://en.cppreference.com/w/cpp/language/operator_arithmetic
For the binary operators (except shifts), if the promoted operands
have different types, additional set of implicit conversions is
applied, known as usual arithmetic conversions with the goal to
produce the common type (also accessible via the std::common_type type
trait)
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.