是否可以在不使用 SFINAE 或编写多个版本的情况下完美转发"non-generic"类型?

Is it possible to perfectly forward a "non-generic" type without using SFINAE or writing multiple versions?

本文关键字:情况下 版本 完美 转发 类型 non-generic SFINAE 是否      更新时间:2023-10-16

我了解完美转发在通常情况下是如何工作的:

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

在不使用SFINAE或编写多个版本的情况下,是否可以完美地转发"非泛型"类型,例如某种形式的std::string

/* 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来限制它(在这种情况下,我可以自己解决一些问题(,但我想知道是否有一些简单的方法我遗漏了。

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

如果你的函数只采用一种指定的类型,最好只创建两个函数,不要试图用技巧巧妙地使用语言。

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

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

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级别上处理这些类型。

#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)); }
相关文章: