【问题标题】:Forwarding reference which binds to only one type?仅绑定到一种类型的转发引用?
【发布时间】:2020-11-07 08:38:29
【问题描述】:

我想要一个只绑定到一种类型的转发引用。我可以使用静态断言, 但我想知道是否有更优雅的 (C++14/17) 方式来做到这一点。

这里是一个例子:

#include <iostream>
#include <string>
#include <type_traits>

template<class T> 
void f(T&& x) {
    // Is there a more elegant way to check for the type than the static_assert?
    static_assert(std::is_same<std::string, typename std::remove_cv_t<std::remove_reference_t<T>>>::value);
    x = x + "Bar";   
    std::cout << x << std::endl;
}

int main()
{
  std::string name("Foo");
  f(name);
  f(std::move(name));
}

【问题讨论】:

  • 您忘记将std::remove_cv_t 应用于remove_reference 的结果。
  • requires (std::is_same_v&lt;std::string, typename std::remove_cv_t&lt;std::remove_reference_t&lt;T&gt;&gt;&gt;)怎么样
  • @asmmo:谢谢。但我坚持使用 C++14/17。我更新了问题以澄清。
  • 您可以将检查移至第二个模板参数并依赖 SFINAE,但我会说这是最好的,因为您会收到清晰直接的错误消息。还有什么比 1 个 static_assert 更优雅的解决方案?

标签: c++ c++14 perfect-forwarding


【解决方案1】:

您可以使用std::enable_if进行编译时检查,如下

template<class T>
std::enable_if_t<std::is_same_v<std::string, typename std::remove_cv_t<std::remove_reference_t<T>>>, void> f(T&& x) {
    x = x + "Bar";
    std::cout << x << std::endl;
}

如果你能用c++20就更好了,如下

template<class T>
void f(T&& x)requires(std::is_same_v<std::string, typename std::remove_cv_t<std::remove_reference_t<T>>>) {
    x = x + "Bar";
    std::cout << x << std::endl;
}

【讨论】:

    【解决方案2】:

    C++20 方式:

    template <typename T>
    requires std::same_as<std::string, std::remove_cvref_t<T>>
    void f(T &&x) {}
    

    C++17 方式:

    template <
        typename T,
        std::enable_if_t<
            std::is_same_v<
                std::string,
                std::remove_cv_t<std::remove_reference_t<T>>
            >,
            std::nullptr_t
        > = nullptr
    >
    void f(T &&x) {}
    

    C++14 的方式与 C++17 相同,只是你必须使用std::same_as&lt;...&gt;::value 而不是std::is_same_v

    【讨论】:

      【解决方案3】:

      我也遇到过这个问题,直到 c++20 才找到解决方案,仍然不完美。

      template<typename T>
      concept StringRef = std::is_same<std::string, typename std::remove_cv_t<std::remove_reference_t<T>>>::value;
      
      void f(StringRef auto &&x)
      {
          // ...
      }
      

      【讨论】:

      • 这不是转发参考
      • 我认为typename std::remove_cv_t 无效,您需要删除typename
      猜你喜欢
      • 1970-01-01
      • 2017-08-28
      • 2014-07-29
      • 1970-01-01
      • 2019-02-08
      • 2011-11-13
      • 1970-01-01
      • 2012-04-06
      • 2019-01-29
      相关资源
      最近更新 更多