c++ - 从 C++ 模板中的非 const 左值引用推导出 const 左值引用

标签 c++ c++11 templates perfect-forwarding template-argument-deduction

假设您有以下一对函数:

void f(const int&) { 
    // Do something, making a copy of the argument.
}

void f(int&&) { 
    // Do the same thing, but moving the argument.
}

它们相当冗余——函数之间的唯一区别在于它们是复制还是移动参数。当然,我们可以通过将其重写为单个模板函数来做得更好:

template<typename T> 
void g(T&&) { 
    // Do something, possibly using std::forward to copy or move the argument.
}

这行得通,并且是实践中常用的习惯用法。但是模板可能会被实例化为三个函数,而不是我们上面的两个。我们可以使用以下代码验证这种情况:

#include <iostream>

template<typename T> constexpr char *type = nullptr;
template<> constexpr const char *type<int&> = "int&";
template<> constexpr const char *type<const int&> = "const int&";
template<> constexpr const char *type<int> = "int";

template<typename T> 
void g(T&&) { 
    std::cout << reinterpret_cast<void*>(&g<T>)
              << " = &g<" << type<T> << ">" << std::endl;
}

int main() {
    int i = 0;
    const int& cr = 0;

    g(i);
    g(cr);
    g(0);

    return 0;
}

/*
Prints:

0x100f45080 = &g<int&>
0x100f45100 = &g<const int&>
0x100f45180 = &g<int>
*/

这为 T = int& 的情况添加了第三个函数。 ,我们在使用非模板函数时没有 f多于。在这种情况下,我们实际上不需要函数的这个非常量左值引用版本——给定f。足以满足我们最初的需求——这会增加我们代码的大小,尤其是当我们有许多以这种方式编写的相互调用的模板函数时。

有没有办法写出我们的函数g上面这样编译器会自动推断出T = const int&什么时候g(i)在我们的示例代码中调用?即,我们不必手动编写 g<const int&>(i) 的方式但仍能获得所需的行为。

最佳答案

说“前向引用”(“通用引用”)优于专用重载是一种主观的观点。在很多情况下确实如此,但如果您想完全控制它们,它们将无法完成所有工作。

您可以明确确保用户不会传递非常量左值引用,方法是添加

    static_assert(!std::is_lvalue_reference<T>::value || std::is_const<typename std::remove_reference<T>::type>::value, "only call g with const argument");

在 g 中,但这并不是在所有情况下都是很好的解决方案。

或者您执行对 vector::push_back(...) 所做的操作并提供显式重载——但这是您的起点,请参阅 https://en.cppreference.com/w/cpp/container/vector/push_back .

“正确”答案仅取决于您的要求。

编辑: @Sjoerd 的建议类似于:

template <typename T>
class aBitComplicated {
public:
 void func(T&& v) { internal_func(std::forward<T>(v)); }
 void func(const T& v) { internal_func(v); }
private:
 template <typename U>
 void internal_func(U&& v) { /* your universal code*/ }
};

还有一些更复杂/更复杂的版本,但这里应该是实现您要求的最简单的版本。

关于c++ - 从 C++ 模板中的非 const 左值引用推导出 const 左值引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55033845/

相关文章:

c++ - GCC 和 clang (SFINAE) 之间的重载解析行为差异

c++ - Boost Log 清除日志文件

c++ - 使 'const' 使用类型特征的结果

php - 用于管理显示哪些内容的模板系统?

c++ - 一个 std::shared_ptr<> 的 std::tuple<> 不起作用?

c++ - 为什么大括号初始值设定项的自动和模板类型推导不同?

templates - 如何在外部文件中定义 Handlebar.js 模板

c++ - 如何强制 C++ 编译器使用特定的 CRT 版本?

c++ - 如何从该文件中的不同行加载数据?

c++ - 已修复尝试在反转数组时修复损坏的代码