Visual C ++ 2010, rvalue link error?

Is this a bug in Visual C ++ 2010 or the correct behavior?

template<class T> T f(T const &r) { return r; } template<class T> T f(T &&r) { static_assert(false, "no way"); //< line # 10 return r; } int main() { int y = 4; f(y); //< line # 17 } 

I thought that the function f (T & &) should never be called, but it is called with T = int &. Output:

  main.cpp (10): error C2338: no way
           main.cpp (17): see reference to function template instantiation 'T f (T)' being compiled
           with
           [
               T = int &
           ]

Update 1 Do you know any C ++ x0 compiler as a reference? I tried a trial online test but could not compile the r-value link.

Update 2 Workaround (using SFINAE):

 #include <boost/utility/enable_if.hpp> #include <boost/type_traits/is_reference.hpp> template<class T> T f(T &r) { return r; } template<class T> typename ::boost::disable_if< ::boost::is_reference<T>, T>::type f(T &&r) { static_assert(false, "no way"); return r; } int main() { int y = 4; f(y); // f(5); // generates "no way" error, as expected. } 

Update 3 Some of the compilers run on static_assert (false, "no way"), even if the function template is not instantiated. Workaround (thanks to @Johannes Schaub - litb)

 template<class T> struct false_ { static bool const value = false; }; ... static_assert(false_<T>::value, "no way"); 

or

 static_assert(sizeof(T) == sizeof(T), "no way"); 
+4
source share
2 answers

As I understand it (and I'm probably not quite right, the specification is a bit complicated), rules for deducting a type of template are being negotiated against you.

First, the compiler tries to replace all the templates (it still does not select at the moment, just looking for options) and gets:

  • T const &r matches int lvalue with T = int , creating f(int const &)
  • T &&r matches int lvalue with T = int& and int & && reduces to int& , creating f(int &) (there are rules that say in spec ).

Now you need to choose the correct overload, and later is better, because the first is different from cv-qualification, and later is not. This is also the reason why when you remove const you get an ambiguous overload error - overloads end the same way.

Ad Update1 : gcc supports many C ++ 0x features . You can get embedded windows from mingw or use cygwin .

Ad Update2 . If you really need separate overloads for rvalue and lvalue, this is the only option. But most templates do the right thing only with any link, possibly using std::forward to ensure that the functions they call are correctly resolved depending on whether they get the value rvalue or lvalue).

+5
source

Your fix does not solve the problem when running static_assert . static_assert(false, ...) will still be run for compilers that parse patterns during definition (most of them).

They will see that any creation of a function template will be poorly formed, and the Standard allows them to give an error for the template itself, and most of them will.

To do this, you need to make the expression dependent so that the compiler does not know when it parses a template that it will always consider false. for instance

 template<class> struct false_ { static bool const value = false; }; template<class T> T f(T &&r) { static_assert(false_<T>::value, "no way"); //< line # 10 return r; } 
+3
source

Source: https://habr.com/ru/post/1340274/


All Articles