3

我了解在通常情况下完美转发的工作原理:

template <typename T> 
void f(T &&arg) { 
  E(std::forward<T>(arg)));
}

是否可以完美地转发“非通用”类型,例如某种形式的std::string不使用 SFINAE 或编写多个版本?

/* Likely some kind of template. */
/* template <typename T> */
void f(/* Something goes here*/ arg) {
  E(std::forward</* Something goes here. */>(arg);
}

以下应该是正确的:

f(std_str_obj); // Lvalue forwarded as const lvalue ref.
f("hello"); // Temporary forwarded as rvalue reference.
f(1); // Error, not a std::string or convertible to std::string.

我怀疑唯一的方法是仍然编写一个函数模板并使用某种形式的 SFINAE 来限制它(在这种情况下我可以自己想办法),但我想知道是否有一些简单的方法可以让我我失踪了。

4

3 回答 3

1

不,这样的事情是不可能的。

如果你的函数只采用一种指定的类型,最好只创建两个函数,而不是试图用技巧来超越语言。

如果使用模板,f(1);则将 int 设置为模板参数。那不是你想要的。

于 2014-05-02T05:53:33.633 回答
0

除非我遗漏了什么,否则这应该适用于您正在寻找的东西。

void f(std::string&& arg)   // Take care of rvalues
{
  E(std::forward<std::string&&>(arg));
}

void f(std::string const& arg)   // Take care of lvalues
{
  E(std::forward<std::string const&>(arg));
}

我能够使用以下程序对其进行测试:

#include <iostream>
#include <string>
#include <utility>

void E(std::string const& s)
{
   std::cout << "Came to E(std::string const& )\n";
}

void E(std::string&& s)
{
   std::cout << "Came to E(std::string&& )\n";
}

void f(std::string&& arg)   // Take care of rvalues
{
   E(std::forward<std::string&&>(arg));
}

void f(std::string const& arg)   // Take care of lvalues
{
   E(std::forward<std::string const&>(arg));
}

int main()
{
   std::string s1("abcd");
   f(s1);
   f("xyx");
}

我从运行程序中得到的输出:

来到 E(std::string const& )
来到 E(std::string&& )

更新

用函数模板替换 的两个重载实现f也同样有效。

template <typename T>
void f(T&& arg)
{
   E(std::forward<T>(arg));
}

int main()
{
   std::string s1("abcd");
   f(s1);
   f("xyx");
}

如果我添加f(1)main,则会出现编译器错误,因为没有重载E可以使用它。如果E它本身是一个函数模板,那么该策略将不起作用。

我认为,底线是你必须阻止使用任何东西的能力,但只能通过不提供在级别或std::string级别处理此类类型的能力。fE

于 2014-05-02T05:33:45.647 回答
0
#include <utility>
#include <type_traits>

template <
    class T
  , class = typename std::enable_if<
         std::is_convertible<std::decay_t<T>, std::string const&>::value
      || std::is_convertible<std::decay_t<T>, std::string     &&>::value
    >::type
>
void f (T&& t) { E (std::forward<T> (t)); }
于 2014-10-14T22:22:52.410 回答