lundi 28 décembre 2015

Function with universal reference argument not being used when called with lvalue

Consider this simple code snippet:

static void Foo(std::string&& arg) {
  printf("(universal reference) = %s\n", arg.c_str());
}

static void Foo(const std::string&& arg) {
  printf("(const universal reference) = %s\n", arg.c_str());
}

static void Foo(std::string& arg) {
  printf("(reference) = %s\n", arg.c_str());
}

static void Foo(const std::string& arg) {
  printf("(const reference) = %s\n", arg.c_str());
}

int main(int argc, const char * argv[]) {
  std::string value{"value"};
  const std::string const_value{"const_value"};

  Foo(value);
  Foo(const_value);
  Foo(std::string("temporary"));
  Foo("litteral");
}

The resulting output under Clang is:

(reference) = value
(const reference) = const_value
(universal reference) = temporary
(universal reference) = literal

Why is the value case not using the universal reference version of the function? I thought one of the key benefits of universal references was that they could accept both lvalues and rvalues?

PS: It's not possible to force it either:

static void Foo(std::string&& arg) {
  printf("(universal reference) = %s\n", arg.c_str());
}

//static void Foo(const std::string&& arg) {
//  printf("(const universal reference) = %s\n", arg.c_str());
//}
//
//static void Foo(std::string& arg) {
//  printf("(reference) = %s\n", arg.c_str());
//}
//
//static void Foo(const std::string& arg) {
//  printf("(const reference) = %s\n", arg.c_str());
//}

int main(int argc, const char * argv[]) {
  std::string value{"value"};
  const std::string const_value{"const_value"};

  Foo(value);   <--- FAILS COMPILING: No matching function for call to 'Foo'
//  Foo(const_value);
  Foo(std::string("temporary"));
  Foo("literal");
}

UPDATE: It appears "universal references" are only for templates, not regular functions, which explains why the above is not working as I was expecting.

However here's a version using a templated function:

template<typename T>
static void Foo(T&& arg) {
  printf("%s\n", arg.c_str());
}

int main(int argc, const char * argv[]) {
  std::string value{"value"};
  const std::string const_value{"const_value"};

  Foo<std::string>(value);   <--- FAILS COMPILING: No matching function for call to 'Foo'
  Foo<std::string>(const_value);   <--- FAILS COMPILING: No matching function for call to 'Foo'
  Foo<std::string>(std::string("temporary"));
  Foo<std::string>("literal");
}

Why is the value case still not working through universal references (I understand why the const_value case is not)?

Aucun commentaire:

Enregistrer un commentaire