【问题标题】:How does msvc compiler(and other compilers) knows which std overload to bind to?msvc 编译器(和其他编译器)如何知道要绑定到哪个 std 重载?
【发布时间】:2020-04-15 15:43:26
【问题描述】:

我知道这个问题有两个答案——一个很长很复杂,一个很短很简单。目前,我对后者感兴趣。

我来自 C#/.NET 背景,如果您使用它一段时间(或 Java),您可能会同意我的观点,即每当您使用某些 BCL 类或方法时,相对容易推断出为什么选择某些重载编译器。

C#的简单例子

// lets imagine we have this somewhere in our code
Contract.Requires(e != null);

// we check who implements this method ...

public static void Requires(bool condition); // <-- observing the call its pretty obvious that this method will be chosen instead of the others
public static void Requires<TException>(bool condition, string userMessage) where TException : Exception;
public static void Requires<TException>(bool condition) where TException : Exception;
public static void Requires(bool condition, string userMessage);

如果您还没有弄清楚我仍在尝试学习 C++,那么我将举一个简单的例子,希望在回答完这个问题后我会开始对阅读 std 代码感到更自在。

// we have this call
int ints[5];
std::is_heap(std::begin(ints), std::end(ints));

// first method I tried to unwind was std::begin and std::end
// and this is what I got from Visual Studio as suggestion (and later confirmed by runtime)

template <class _Ty, size_t _Size>
_NODISCARD constexpr _Ty* begin(_Ty (&_Array)[_Size]) noexcept {
    return _Array;
}

template <class _Ty, size_t _Size>
_NODISCARD constexpr _Ty* end(_Ty (&_Array)[_Size]) noexcept {
    return _Array + _Size;
}

// then I checked std::is_heap and I got

template <class _RanIt>
_NODISCARD bool is_heap(_RanIt _First, _RanIt _Last) { // test if range is a heap ordered by operator<
    return _STD is_heap(_First, _Last, less<>());
}

在我做出一些假设之前,我想我会提醒你我是 C++ 新手的免责声明。

  1. (&amp;_Array)[_Size] 是否以某种方式帮助编译器理解传递给某个函数(或函数模板)的参数将是数组(类似于 type_traits)?
  2. 在第二个静态绑定 (std::is_heap) 中,是不是因为模板是编译时的,因此建议的函数看起来不像您期望的那样,例如,is_heap(int*, int*),因为这些是调用它的参数类型?

【问题讨论】:

    标签: c++ stl std static-linking


    【解决方案1】:

    (&_Array)[_Size] 是否有助于编译器理解传递给某个函数(或函数模板)的参数将是数组(类似于 type_traits)?

    _Ty (&amp;_Array)[_Size] 是一个数组参数(_Ty[_Size]),通过引用传递并命名为_Array。它看起来很奇怪'cos C,信不信由你。与类型特征无关。

    我不太了解您的第二个问题,但编译器会选择最符合您的参数的重载。关于此处“最佳”含义的规则很复杂,但在标准中进行了描述。如果多个重载同样匹配,则您的调用不明确,程序将无法编译。模板确实使这一点变得复杂,因为它们本质上引入了许多个可能的候选者。我同意模板很可能在此处使用_RanIt=int* 进行实例化,结果与您的调用完美匹配。

    【讨论】:

    • 所以我的第二个猜测是正确的,那么很好,不确定我是否理解第一个,但我会给它一些时间来深入了解
    • @kuskmen 我认为这只是让您感到困惑的语法。按值传递的int 类似于void foo(int x)。按值传递的_Ty 看起来像void foo(_Ty x)。通过引用传递的_Ty 看起来像void foo(_Ty&amp; x)。通过引用传递的_Ty[_Size] 看起来像void foo(_Ty (&amp;x)[_Size])。就是这样。查找“螺旋规则”以获取有关复杂声明的更多信息(语法/规则继承自 C)
    • @kuskmen N.B.一个“按值传递”的数组(即void foo(_Ty x[_Size]))是一个谎言!这相当于void foo(_Ty* x),即使数组不是指针。再次,责怪 C。:)
    • @kuskmen 是的,数组的大小是其类型的一部分。 int[5]int[10] 不同。
    • C# 完全不同;我建议不要在两种语言之间进行比较。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-01
    • 1970-01-01
    • 2010-09-17
    • 2011-05-23
    • 1970-01-01
    相关资源
    最近更新 更多