Why template argument cannot be deduced in this context? - c++

Could anyone explain why compilers (g++, visual c++) fail to deduce the template argument in this case?
struct MyClass
{
void Foo(int x)& {}
void Foo(int x)&& {}
};
template<typename T>
void CallFoo(void(T::*func)(int)&)
{
//create instance and call func
}
int main()
{
CallFoo(&MyClass::Foo); // Fails to deduce T
}
Why compilers cannot deduce T to MyClass? This happens only for methods overloaded by ref qualifiers. If a method is overloaded by const-ness or parameter types, everything works fine.
It seems that only Clang can deduce T in this case.

Summarizing discussion in the comments:
the support for reference-qualified member functions as template arguments is a relatively new feature for some compilers. However, the latest versions of most compilers will compile such code.
For example:
#include <iostream>
struct MyClass
{
void Foo(int) const &
{
std::cout << "calling: void Foo(int) const &\n";
}
void Foo(int) const &&
{
std::cout << "calling: void Foo(int) const &&\n";
}
};
template<typename T>
void CallFoo_lvalue(void (T::*foo)(int) const &)
{
T temp;
(temp.*foo)(0);
}
template<typename T>
void CallFoo_rvalue(void (T::*foo)(int) const &&)
{
(T{}.*foo)(0);
}
int main()
{
CallFoo_lvalue(&MyClass::Foo);
CallFoo_rvalue(&MyClass::Foo);
}
Will compile with:
gcc (works from 7.0.0)
Visual C++ (works with v19.10.24903.0)
producing the following output:
calling: void Foo(int) const &
calling: void Foo(int) const &&
For those who are wondering what & and && are for: here's the quote from #JustinTime:
Basically, & is the lvalue ref-qualifier, and && is the rvalue
ref-qualifier (binds to temporary object); in his example, MyClass m;
m.Foo(3); would call the top one, while MyClass{}.Foo(3); would call
the bottom one. They act on the implicit object parameter; lvalue
ref-qualifier binds to lvalue reference, and rvalue ref-qualifier
binds to rvalue reference (functions that have neither take the
parameter as lvalue reference, but let it bind to either). Note that
they don't actually change *this's type.

If you want your template to bind to different reference types, you need to use the universal reference
template<typename T>
void func(T&& arg)
{
other_func(std::forward<T>(arg));
}
That will bind to either lvalue or rvalue references. std::forward will make sure the appropriate reference is used in subsequent calls. I'm not sure how to fit the double ampersand into your code, but maybe just
template<typename T>
void CallFoo(void(T::*func)(int)&&)
Perhaps better would be
template<typename func_t>
void CallFoo(func_t && f)
{
call(std::forward<func_t>(f));
}
template<typename func_t>
void call(typename std::remove_reference<func_t> & f)
{
f();
}
template<typename func_t>
void call(typename std::remove_reference<func_t> && f)
{
f();
}
or whatever syntax you need to invoke a function pointer, maybe *f();
And if you want to pass arguments as well:
template<typename func_t, typename ... args_t>
void CallFoo(func_t && f, args_t && ... args)
{
call(std::forward<func_t>(f), std::forward<args_t>(args)...);
}
template<typename func_t, typename ... args_t>
void call(typename std::remove_reference<func_t> & f, args_t && ... args)
{
f(std::forward<args_t>(args)...);
}
template<typename func_t, typename ... args_t>
void call(typename std::remove_reference<func_t> && f, args_t && ... args)
{
f(std::forward<args_t>(args)...);
}

Related

c++ : variadic template and function overloading

see example below live : https://onlinegdb.com/Hkg6iQ3ZNI
#include <iostream>
#include <utility>
#include <type_traits>
class A
{
public:
A(int v=-10):v_(v){}
void print()
{
std::cout << "called A: " << v_ << std::endl;
}
private:
int v_;
};
void f(int v)
{
std::cout << "called f: " << v << std::endl;
}
template<typename T,typename ... Args>
void run(A&& a,
T&& t,
Args&& ... args)
{
a.print();
t(std::forward<Args>(args)...);
}
template<typename T,typename ... Args>
void run(T&& t,
Args&& ... args)
{
run(A(),
std::forward<T>(t),
std::forward<Args>(args)...);
}
int main()
{
int v_function=1;
int v_a = 2;
run(f,v_function);
return 0;
}
The code above compiles, runs and print (as expected):
called A: -10
called f: 1
but if the main function is modified to:
int main()
{
int v_function=1;
int v_a = 2;
run(f,v_function);
// !! added lines !!
A a(v_a);
run(a,f,v_function);
return 0;
}
then compilation fails with error:
main.cpp:30:6: error: no match for call to ‘(A) (void (&)(int), int&)’
t(std::forward(args)...);
~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
which seems to indicate that even when an instance of A is passed as first argument, the overload function
void(*)(T&&,Args&&...)
is called, and not
void(*)(A&&,T&&,Args&&...)
With
template<typename T,typename ... Args>
void run(A&& a,
T&& t,
Args&& ... args)
a is not a forwarding reference, but an rvalue reference. That means when you do run(a,f,v_function); that function will not be selected because a is an lvalue and those can't be bound to rvalue references. There are two quick ways to fix this. First, use std::move on a like
run(std::move(a),f,v_function);
but this isn't great. a isn't actually moved in the function so you are kind of violating the principle of least surprise.
The second option is to make A in the function a template type so it becomes a forwarding reference and then you can constrain it to be of type A like
template<typename A_, typename T,typename ... Args, std::enable_if_t<std::is_same_v<std::decay_t<A_>, A>, bool> = true>
void run(A_&& a,
T&& t,
Args&& ... args)
{
a.print();
t(std::forward<Args>(args)...);
}
Your code works, if you are calling run with an rvalue.
Playable example here.
As NathanOliver already sad: void run(A&& a, T&& t, Args&& ... args) expects an rvalue reference.
Basic idea of an rvalue reference: You are passing an rvalue to a function (e.g. a string literal). That value will be copied to the function. This work is unnecessary. Instead, you are just "moving" the reference to that value, so that it is "owned" by a different part of your program. Move constructors are a good starting point for understanding this problem.

How do two overloaded std::forward work? [duplicate]

This question already has an answer here:
Why does std::forward have two overloads?
(1 answer)
Closed 5 years ago.
I have found in std library the following implementation of std::forward:
// TEMPLATE FUNCTION forward
template<class _Ty> inline
constexpr _Ty&& forward(
typename remove_reference<_Ty>::type& _Arg) _NOEXCEPT
{ // forward an lvalue as either an lvalue or an rvalue
return (static_cast<_Ty&&>(_Arg));
}
template<class _Ty> inline
constexpr _Ty&& forward(
typename remove_reference<_Ty>::type&& _Arg) _NOEXCEPT
{ // forward an rvalue as an rvalue
static_assert(!is_lvalue_reference<_Ty>::value, "bad forward call");
return (static_cast<_Ty&&>(_Arg));
}
First function works obviously, but for second I cannot find usefull example.
If I try to do something like this:
template<class _Ty> inline
constexpr _Ty&& my_forward(
typename std::remove_reference<_Ty>::type&& _Arg) _NOEXCEPT
{ // forward an rvalue as an rvalue
static_assert(!std::is_lvalue_reference<_Ty>::value, "bad forward call");
return (static_cast<_Ty&&>(_Arg));
}
template<typename T>
T getRValue()
{
return std::remove_reference<T>::type{};
}
template<typename T>
void setValue(T && i)
{
my_forward<T>(getRValue<T>());
}
int main()
{
int i = 1;
setValue(i);
}
to check when second function is called, I have got the error:
Error C2664 '_Ty my_forward<T>(int &&) noexcept': cannot convert argument 1 from 'int' to 'int &&'
Does anybody know in which case second overloaded function (in my terms my_forward) is called ?
Or may be some good example for it ?
By the way my compiler is MSVC 2015
Thanks, all for help !!
int bad_forward_call() {
return std::forward<int&>(7);
}
this will invoke that version.
Note I'm forwarding an rvalue as an lvalue. Not allowed.
Your getRValue fails to get an rvalue if T is a reference type.
I have found cases in which this function is called:
my_forward<int&>(8); // This calls forward(typename remove_reference<_Ty>::type&& _Arg)
But it won't compile 'cause we try convert rvalue to lvalue
my_forward<int&&>(8); // This calls forward(typename remove_reference<_Ty>::type&& _Arg)
But it compiles successfully
If it may be useful for somebody, the purpose of std::forward is to forward operation to another class or function.
Consider the following example:
template<typename T>
void precompute(T & t)
{
std::cout << "lvalue reference";
}
template<typename T,
std::enable_if_t<!std::is_reference<T>::value, bool> = true>
void precompute(T && t)
{
std::cout << "rvalue reference";
}
template<typename T>
void calculate(T && t)
{
precompute(t); // Every time called precompute(T & t)
}
or like this:
template<typename T>
void precompute(T & t)
{
std::cout << "lvalue reference";
}
template<typename T,
std::enable_if_t<!std::is_reference<T>::value, bool> = true>
void precompute(T && t)
{
std::cout << "rvalue reference";
}
template<typename T>
void calculate(T && t)
{
precompute(std::move(t)); // Every time called precompute(T && t)
}
As you can see we have a problem !! Neither of two examples satisfied us.
In first example every time will be called lvalue function and nothing can be done to call first with rvalue.
In second example every time will be called rvalue function and nothing can be done to call first with lvalue.
The solution is to forward making decision to the called function:
template<typename T>
void precompute(T & t)
{
std::cout << "lvalue reference";
}
template<typename T,
std::enable_if_t<!std::is_reference<T>::value, bool> = true>
void precompute(T && t)
{
std::cout << "rvalue reference";
}
template<typename T>
void calculate(T && t)
{
precompute(std::forward<T>(t)); // Will be called either precompute(T & t) or precompute(T && t) depends on type of t
}
In this case we have to be sure that will be called appropriate version.
That is why we forward (means: "Please, check type of t and if it is rvalue -> call rvalue version of function, and if it is lvalue -> call lvalue version of function") this operation to called function.

In std::forward how does it accept rvalue?

Looking at Scott Meyer's Effective Modern C++ pages 200-201, the suggested simplified implementation of std::forward could be (did see the proper implementation elsewhere):
template <typename T>
T&& forward(std::remove_reference_t<T>& param)
{ return static_cast<T&&>(param); }
And when accepting an rvalue Widget, it becomes:
Widget&& forward(Widget& param)
{ return static_cast<Widget&&>(param); }
Now, if you take that substituted code, and do:
struct Widget { };
Widget&& forward(Widget& param)
{ return static_cast<Widget&&>(param); }
template <typename T>
void G(T&& uref)
{ }
template <typename T>
void F(T&& uref)
{ G(forward(uref)); }
int main()
{
Widget x;
F(std::move(x));
}
What I can't wrap my head around, and didn't see a direct answer on SO yet, is: in forward how does parameter Widget& param manage to accept Widget&& from F()? Normally gcc-5.0 would complain like so with non-template code:
error: invalid initialization of non-const reference of type ‘Widget&’ from an rvalue of type ‘std::remove_reference::type {aka Widget}’
(Question #27501400 nearly touches the topic, but not quite. It shows the standard as having both lvalue & and rvalue && versions.)
"Named rvalue references are lvalues",
so example works fine as noted in a comment.
Nevertheless your code could be modified to
template <typename T>
void F(T && uref)
{
G(forward(move(uref)));
}
which is accepted by another overload (compare):
template<typename T>
T && forward(typename std::remove_reference<T>::type & t)
{
return static_cast<T &&>(t);
}
template<typename T>
T && forward(typename std::remove_reference<T>::type && t)
{
static_assert(!std::is_lvalue_reference<T>::value, "T is an lvalue reference");
return static_cast<T &&>(t);
}
The second overload will be used for rvalue. It works if T is Widget or Widget && and the assert fails for Widget &.

How do I avoid implicit conversions on non-constructing functions?

How do I avoid implicit casting on non-constructing functions?
I have a function that takes an integer as a parameter,
but that function will also take characters, bools, and longs.
I believe it does this by implicitly casting them.
How can I avoid this so that the function only accepts parameters of a matching type, and will refuse to compile otherwise?
There is a keyword "explicit" but it does not work on non-constructing functions. :\
what do I do?
The following program compiles, although I'd like it not to:
#include <cstdlib>
//the function signature requires an int
void function(int i);
int main(){
int i{5};
function(i); //<- this is acceptable
char c{'a'};
function(c); //<- I would NOT like this to compile
return EXIT_SUCCESS;
}
void function(int i){return;}
*please be sure to point out any misuse of terminology and assumptions
Define function template which matches all other types:
void function(int); // this will be selected for int only
template <class T>
void function(T) = delete; // C++11
This is because non-template functions with direct matching are always considered first. Then the function template with direct match are considered - so never function<int> will be used. But for anything else, like char, function<char> will be used - and this gives your compilation errrors:
void function(int) {}
template <class T>
void function(T) = delete; // C++11
int main() {
function(1);
function(char(1)); // line 12
}
ERRORS:
prog.cpp: In function 'int main()':
prog.cpp:4:6: error: deleted function 'void function(T) [with T = char]'
prog.cpp:12:20: error: used here
This is C++03 way:
// because this ugly code will give you compilation error for all other types
class DeleteOverload
{
private:
DeleteOverload(void*);
};
template <class T>
void function(T a, DeleteOverload = 0);
void function(int a)
{}
You can't directly, because a char automatically gets promoted to int.
You can resort to a trick though: create a function that takes a char as parameter and don't implement it. It will compile, but you'll get a linker error:
void function(int i)
{
}
void function(char i);
//or, in C++11
void function(char i) = delete;
Calling the function with a char parameter will break the build.
See http://ideone.com/2SRdM
Terminology: non-construcing functions? Do you mean a function that is not a constructor?
8 years later (PRE-C++20, see edit):
The most modern solution, if you don't mind template functions -which you may mind-, is to use a templated function with std::enable_if and std::is_same.
Namely:
// Where we want to only take int
template <class T, std::enable_if_t<std::is_same_v<T,int>,bool> = false>
void func(T x) {
}
EDIT (c++20)
I've recently switched to c++20 and I believe that there is a better way. If your team or you don't use c++20, or are not familiar with the new concepts library, do not use this. This is much nicer and the intended method as outlines in the new c++20 standard, and by the writers of the new feature (read a papers written by Bjarne Stroustrup here.
template <class T>
requires std::same_as(T,int)
void func(T x) {
//...
}
Small Edit (different pattern for concepts)
The following is a much better way, because it explains your reason, to have an explicit int. If you are doing this frequently, and would like a good pattern, I would do the following:
template <class T>
concept explicit_int = std::same_as<T,int>;
template <explicit_int T>
void func(T x) {
}
Small edit 2 (the last I promise)
Also a way to accomplish this possibility:
template <class T>
concept explicit_int = std::same_as<T,int>;
void func(explicit_int auto x) {
}
Here's a general solution that causes an error at compile time if function is called with anything but an int
template <typename T>
struct is_int { static const bool value = false; };
template <>
struct is_int<int> { static const bool value = true; };
template <typename T>
void function(T i) {
static_assert(is_int<T>::value, "argument is not int");
return;
}
int main() {
int i = 5;
char c = 'a';
function(i);
//function(c);
return 0;
}
It works by allowing any type for the argument to function but using is_int as a type-level predicate. The generic implementation of is_int has a false value but the explicit specialization for the int type has value true so that the static assert guarantees that the argument has exactly type int otherwise there is a compile error.
Maybe you can use a struct to make the second function private:
#include <cstdlib>
struct NoCast {
static void function(int i);
private:
static void function(char c);
};
int main(){
int i(5);
NoCast::function(i); //<- this is acceptable
char c('a');
NoCast::function(c); //<- Error
return EXIT_SUCCESS;
}
void NoCast::function(int i){return;}
This won't compile:
prog.cpp: In function ‘int main()’:
prog.cpp:7: error: ‘static void NoCast::function(char)’ is private
prog.cpp:16: error: within this context
For C++14 (and I believe C++11), you can disable copy constructors by overloading rvalue-references as well:
Example:
Say you have a base Binding<C> class, where C is either the base Constraint class, or an inherited class. Say you are storing Binding<C> by value in a vector, and you pass a reference to the binding and you wish to ensure that you do not cause an implicit copy.
You may do so by deleting func(Binding<C>&& x) (per PiotrNycz's example) for rvalue-reference specific cases.
Snippet:
template<typename T>
void overload_info(const T& x) {
cout << "overload: " << "const " << name_trait<T>::name() << "&" << endl;
}
template<typename T>
void overload_info(T&& x) {
cout << "overload: " << name_trait<T>::name() << "&&" << endl;
}
template<typename T>
void disable_implicit_copy(T&& x) = delete;
template<typename T>
void disable_implicit_copy(const T& x) {
cout << "[valid] ";
overload_info<T>(x);
}
...
int main() {
Constraint c;
LinearConstraint lc(1);
Binding<Constraint> bc(&c, {});
Binding<LinearConstraint> blc(&lc, {});
CALL(overload_info<Binding<Constraint>>(bc));
CALL(overload_info<Binding<LinearConstraint>>(blc));
CALL(overload_info<Binding<Constraint>>(blc));
CALL(disable_implicit_copy<Binding<Constraint>>(bc));
// // Causes desired error
// CALL(disable_implicit_copy<Binding<Constraint>>(blc));
}
Output:
>>> overload_info(bc)
overload: T&&
>>> overload_info<Binding<Constraint>>(bc)
overload: const Binding<Constraint>&
>>> overload_info<Binding<LinearConstraint>>(blc)
overload: const Binding<LinearConstraint>&
>>> overload_info<Binding<Constraint>>(blc)
implicit copy: Binding<LinearConstraint> -> Binding<Constraint>
overload: Binding<Constraint>&&
>>> disable_implicit_copy<Binding<Constraint>>(bc)
[valid] overload: const Binding<Constraint>&
Error (with clang-3.9 in bazel, when offending line is uncommented):
cpp_quick/prevent_implicit_conversion.cc:116:8: error: call to deleted function 'disable_implicit_copy'
CALL(disable_implicit_copy<Binding<Constraint>>(blc));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Full Source Code: prevent_implicit_conversion.cc
Well, I was going to answer this with the code below, but even though it works with Visual C++, in the sense of producing the desired compilation error, MinGW g++ 4.7.1 accepts it, and invokes the rvalue reference constructor!
I think it must be a compiler bug, but I could be wrong, so – anyone?
Anyway, here's the code, which may turn out to be a standard-compliant solution (or, it may turn out that that's a thinko on my part!):
#include <iostream>
#include <utility> // std::is_same, std::enable_if
using namespace std;
template< class Type >
struct Boxed
{
Type value;
template< class Arg >
Boxed(
Arg const& v,
typename enable_if< is_same< Type, Arg >::value, Arg >::type* = 0
)
: value( v )
{
wcout << "Generic!" << endl;
}
Boxed( Type&& v ): value( move( v ) )
{
wcout << "Rvalue!" << endl;
}
};
void function( Boxed< int > v ) {}
int main()
{
int i = 5;
function( i ); //<- this is acceptable
char c = 'a';
function( c ); //<- I would NOT like this to compile
}
I first tried PiotrNycz's approach (for C++03, which I'm forced to use for a project), then I tried to find a more general approach and came up with this ForcedType<T> template class.
template <typename T>
struct ForcedType {
ForcedType(T v): m_v(v) {}
operator T&() { return m_v; }
operator const T&() const { return m_v; }
private:
template <typename T2>
ForcedType(T2);
T m_v;
};
template <typename T>
struct ForcedType<const T&> {
ForcedType(const T& v): m_v(v) {}
operator const T&() const { return m_v; }
private:
template <typename T2>
ForcedType(const T2&);
const T& m_v;
};
template <typename T>
struct ForcedType<T&> {
ForcedType(T& v): m_v(v) {}
operator T&() { return m_v; }
operator const T&() const { return m_v; }
private:
template <typename T2>
ForcedType(T2&);
T& m_v;
};
If I'm not mistaken, those three specializations should cover all common use cases. I'm not sure if a specialization for rvalue-reference (on C++11 onwards) is actually needed or the by-value one suffices.
One would use it like this, in case of a function with 3 parameters whose 3rd parameter doesn't allow implicit conversions:
function(ParamType1 param1, ParamType2 param2, ForcedType<ParamType3> param3);

Perfect Forwarding in C++03

If you have this function
template<typename T> f(T&);
And then try to call it with, let's say an rvalue like
f(1);
Why isn't T just be deduced to be const int, making the argument a const int& and thus bindable to an rvalue?
This is mentioned as a potential solution in the document I linked in the recent C++0x forwarding question.
It would work fairly well, but it breaks existing code. Consider (straight from the document):
template<class A1> void f(A1 & a1)
{
std::cout << 1 << std::endl;
}
void f(long const &)
{
std::cout << 2 << std::endl;
}
int main()
{
f(5); // prints 2 under the current rules, 1 after the change
int const n(5);
f(n); // 1 in both cases
}
Or
// helper function in a header
template<class T> void something(T & t) // #1
{
t.something();
}
// source
#include <vector>
void something(bool) // #2
{
}
int main()
{
std::vector<bool> v(5);
// resolves to #2 under the current rules, #1 after the change
something(v[0]);
}
This also fails to forward the value category (lvalue or rvalue), which isn't much of a problem in C++03. But since this fix could only be done during C++0x, we'd effectively shutting ourselves out from rvalue references when forwarding (a bad thing). We should strive for a better solution.
It is, but only if you declare f to take T const &.
template <typename T> void f(T &);
template <typename T> void g(T const &);
void x() { f(1); } // error: invalid initialization of non-const reference
void y() { g(1); } // no error
And if you declare both f(T &) and f(T const &), it'll choose the const-qualified one:
template <typename T> void f(T &);
template <typename T> void f(T const &);
void x() { f(1); } // no error, calls f(T const &)
Now maybe you're saying “in the first example, why does it generate a temporary of type int for the call to f when it could have generated a temporary of type const int and made the code compile?” The best answer I have for you is that that would be inconsistent with the overload resolution behavior when the argument isn't an integer constant.