标签: overload-resolution

重载分辨率和数组:应该调用哪个函数?

考虑以下程序:

#include <cstddef>
#include <cstdio>

void f(char const*&&)      { std::puts("char const*&&");      } // (1)
void f(char const* const&) { std::puts("char const* const&"); } // (2)

template <std::size_t N>
void f(char const (&)[N])  { std::puts("char const(&)[N]");   } // (3)

int main()
{
    const char data[] = "a";
    f(data);
}
Run Code Online (Sandbox Code Playgroud)

哪个f应该叫?为什么?

三个编译器的最新发布版本不同意这个问题的答案:

  • 当使用g ++ 4.5.2编译程序时调用(1)
  • 使用Visual C++ 2010 SP1编译程序时调用(2)
  • 使用Clang 3.0(trunk 127530)编译程序时调用(3 )

在不同的C++ 0x草案中,重载决策规则是否发生了很大变化?或者,这两个编译器真的完全错了吗?哪个重载是根据最新的C++ 0x草案选择的正确重载?

c++ arrays reference overload-resolution c++11

29
推荐指数
1
解决办法
1665
查看次数

重载解析和模板参数推导 - 为什么 0 很特殊?

在下面的示例中,0它以一种特殊的方式运行:它选择与示例函数调用所期望的不同的重载。我想知道为什么。我的理解也如下。

#include <iostream>

template<typename T>
void f(T a) {
    std::cout << "first" << std::endl;
}

template<typename T>
void f(T* a) {
    std::cout << "second" << std::endl;
}

int main()
{
    f(0);
    f<size_t>(0);
    f<size_t>(0UL);
    
    f(1);
    f<size_t>(1);
}
Run Code Online (Sandbox Code Playgroud)

输出:

first
second
first
first
first
Run Code Online (Sandbox Code Playgroud)

我的理解:

f(0)- 模板参数推导,整数文字0int类型,因此f选择第一个T=int

f<size_t>(0)-带有整数提升的显式模板实例化,选择的类型是T=size_t,选择第一个函数并从到提升0(我在这里错了intsize_t

f<size_t>(0UL)- 与上面相同,但没有升级(0 已经是 type size_t

f(1)- 与 …

c++ templates function-templates overload-resolution template-argument-deduction

28
推荐指数
1
解决办法
1404
查看次数

C++ 0x const RValue引用作为函数参数

我试图理解为什么有人会编写一个带有const右值引用函数.

在下面的代码示例中,const rvalue引用函数的用途是什么(返回"3").为什么重载决策首选const Rvalue高于const LValue引用函数(返回"2").

#include <string>
#include <vector>
#include <iostream>

std::vector<std::string> createVector() { return std::vector<std::string>(); } 

//takes movable rvalue
void func(std::vector<std::string> &&p) { std::cout << "1"; }

//takes const lvalue
void func(const std::vector<std::string> &p)  { std::cout << "2"; }

//takes const rvalue???
//what is the point of const rvalue? if const I assume it is not movable?
void func(const std::vector<std::string> &&p) { std::cout << "3"; }

int main()
{
    func(createVector());
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

c++ rvalue lvalue overload-resolution c++11

27
推荐指数
1
解决办法
3625
查看次数

为什么选择这种转换运算符的重载?

考虑以下代码

struct any
{
    template <typename T>
    operator T &&() const;

    template <typename T>
    operator T &() const;
};
int main()
{
    int a = any{};
}
Run Code Online (Sandbox Code Playgroud)

这里第二个转换运算符由重载决议选择。为什么?

据我了解,这两个运算符分别推导为operator int &&() constoperator int &() const。两者都在可行的功能集中。通读 [over.match.best] 并没有帮助我弄清楚为什么后者更好。

为什么后者的功能比前者好?

c++ language-lawyer overload-resolution c++17

27
推荐指数
2
解决办法
760
查看次数

如何防止 C++ 猜测第二个模板参数?

我正在使用 C++ 库 ( strf ),其中的某处具有以下代码:

namespace strf {
template <typename ForwardIt>
inline auto range(ForwardIt begin, ForwardIt end) { /* ... */ }

template <typename Range, typename CharT>
inline auto range(const Range& range, const CharT* sep) { /* ... */ }
}
Run Code Online (Sandbox Code Playgroud)

现在,我想strf::range<const char*>(some_char_ptr, some_char_ptr + some_length)在我的代码中使用。但是如果我这样做,我会收到以下错误(使用 CUDA 10.1 的 NVCC):

error: more than one instance of overloaded function "strf::range" matches the argument list:
            function template "auto strf::range(ForwardIt, ForwardIt)"
            function template "auto strf::range(const Range &, const CharT *)" …
Run Code Online (Sandbox Code Playgroud)

c++ nvcc overload-resolution c++11 template-argument-deduction

27
推荐指数
2
解决办法
5474
查看次数

在重载决策中,选择使用模糊转换序列的函数是否必然导致调用不正确?

当我研究这个SO问题的答案时,问题出现了.请考虑以下代码:

struct A{
    operator char() const{ return 'a'; }
    operator int() const{ return 10; }
};

struct B {
    void operator<< (int) { }
};

int main()
{
    A a;
    B b;
    b << a;
}
Run Code Online (Sandbox Code Playgroud)

ato 的转换int可以是via,a.operator char()然后是整数提升,也可以是a.operator int()身份转换(即根本没有转换).标准说(§13.3.3.1[over.best.ics]/p10,脚注省略,加粗我的;所有引用均来自N3936):

如果存在几个不同的转换序列,每个转换序列将参数转换为参数类型,则与参数相关联的隐式转换序列被定义为指定为模糊转换序列的唯一转换序列.为了按照13.3.3.2中的描述对隐式转换序列进行排序,模糊转换序列被视为用户定义的序列,与任何其他用户定义的转换序列无法区分.如果选择使用模糊转换序列的函数作为最佳可行函数,则调用将是错误的,因为调用中的一个参数的转换是不明确的.

在这里,B::operator<<(int)是唯一可行的候选者 - 因此是最好的可行候选者,即使参数的转换序列不明确的转换序列.然后,根据粗体句子,调用应该是格式错误的,因为"调用中的一个参数的转换是模糊的".

然而,我测试的编译器(g ++,clang和MSVC)实际上没有报告错误,这是有道理的,因为在通过重载决定选择调用函数之后,函数的"参数(8.3.5)应该被初始化(8.5,12.8) ,12.1)及其对应的参数"(§5.2.2[expr.call]/p4).这个初始化是复制初始化(§8.5[dcl.init]/p15),根据§8.5[dcl.init]/p17,导致新一轮的重载决策,以确定要使用的转换函数:

初始化器的语义如下.的目标类型 是对象或引用的类型被初始化和 源类型是初始化表达式的类型.如果初始化程序不是单个(可能带括号的)表达式,则不定义源类型.

  • [...]
  • 如果目标类型是(可能是cv限定的)类类型:[...]
  • 否则,如果源类型是(可能是cv限定的)类类型,则考虑转换函数.列举了适用的转换函数(13.3.1.5),并通过重载决策(13.3)选择最佳函数.调用如此选择的用户定义转换以将初始化表达式转换为正在初始化的对象.如果转换不能完成或不明确,则初始化是错误的.
  • [...] …

c++ language-lawyer overload-resolution implicit-conversion

26
推荐指数
1
解决办法
660
查看次数

C++中的lambdas重载以及clang和gcc之间的差异

我正在玩一个用C++重载lambdas的技巧.特别:

// For std::function
#include <functional>

// For std::string
#include <string>

// For std::cout
#include <iostream>

template <class... F>
struct overload : F... {
    overload(F... f) : F(f)... {}
};      

template <class... F>
auto make_overload(F... f) {
    return overload<F...>(f...);
}

int main() {

    std::function <int(int,int)> f = [](int x,int y) {
        return x+y;
    };
    std::function <double(double,double)> g = [](double x,double y) {
        return x+y;
    };
    std::function <std::string(std::string,std::string)> h = [](std::string x,std::string y) {
        return x+y;
    };

    auto fgh = make_overload(f,g,h); …
Run Code Online (Sandbox Code Playgroud)

c++ gcc clang overload-resolution c++11

26
推荐指数
2
解决办法
1772
查看次数

为什么具有固定底层类型char的枚举值会解析为fct(int)而不是fct(char)?

在回答有关使用枚举的重载解析的问题时,出现了此问题.

虽然案例long long肯定是MSVC2012NovCTP中的一个错误(根据标准文本和gcc 4.7.1的测试),我无法弄清楚为什么会出现以下行为:

#include <iostream>

enum charEnum : char { A = 'A' };

void fct(char)      { std::cout << "fct(char)"      << std::endl; }
void fct(int)       { std::cout << "fct(int)"       << std::endl; }
void fct(long long) { std::cout << "fct(long long)" << std::endl; }

int main() 
{
    fct('A');
    fct(A);
}
Run Code Online (Sandbox Code Playgroud)

MSVC2012NovCTP和gcc 4.7.1都同意此输出:

fct(char)
fct(int)

A应该转换charEnumchar?为什么A被转换成int

编辑:clang抱怨说这个电话含糊不清,这与我在下面的解释一致; 那说,如果它只被认为是潜在的类型,我仍然会发现它更直观.


两个相关的标准摘录是§7.2/ 9:

枚举器的值或未范围的枚举类型的对象通过整数提升转换为整数(4.5)

并且§4.5/ 4:

其底层类型为固定(7.2)的无范围枚举类型的prvalue可以转换为其基础类型的prvalue.此外,如果可以对其基础类型应用整数提升,则其基础类型固定的未范围枚举类型的prvalue也可以转换为提升的基础类型的prvalue.

因此, …

c++ enums overloading overload-resolution c++11

25
推荐指数
1
解决办法
1768
查看次数

为什么不缩小会影响重载分辨率?

考虑以下:

struct A {
    A(float ) { }
    A(int ) { }
};

int main() {
    A{1.1}; // error: ambiguous
}
Run Code Online (Sandbox Code Playgroud)

这无法编译时出现关于模糊重载的错误A::A.两位候选人都被认为是可行的,因为要求很简单:

第二,为了F成为一个可行的函数,每个参数都应该存在一个隐式转换序列(13.3.3.1),它将该参数转换为相应的参数F.

虽然存在从隐式转换序列doubleint,该A(int )过载不是实际可行的(在规范,非C++ -标准的意义上) -这将涉及一个收缩转换,因此是形成不良.

为什么在确定可行的候选人的过程中不考虑缩小转换?尽管只有一个候选人可行,但是有没有其他情况下过载被认为是模棱两可的?

c++ language-lawyer overload-resolution c++11

25
推荐指数
2
解决办法
736
查看次数

从恰好两个字符串文字构造结构向量(使用一些自定义构造函数)会崩溃。为什么?

你能猜出这个简单程序的输出吗?

\n
#include <vector>\n#include <string>\n#include <exception>\n#include <iostream>\n\nint main()\n{\n    try { \n        struct X {\n            explicit X(int) {}\n            X(std::string) {} // Just to confuse you more...\n        };\n        std::vector<X>{"a", "b"};\n    } catch (std::exception& x) {\n        std::cerr << x.what();\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

好吧,我不能,这花了我一天的时间“研究”,然后才登陆这里,最终从一些复杂的现实生活代码中提取出来(到处都是类型别名,匿名。与非 POD 成员的联合以及手工 -精心策划的演员/导演等,只是为了营造氛围)。

\n

而且……我还是看不出发生了什么!有人可以给一个温柔的提示吗?(希望只是一个盲点。我不再专业地从事 C++ 工作。)

\n

注意:使用(最新的)MSVC/W4和 GCC进行干净编译* -Wall;两者的输出相同(语义上)。

\n

* 即使没有“迷惑读者”这句话。我想我会做噩梦。

\n
\n

(请耐心等待我尽量不将所有内容拼写得更多 \xe2\x80\x94 毕竟,这确实是不言自明的,对吧?除了,对我来说完全相反......)

\n

c++ vector overload-resolution list-initialization

25
推荐指数
1
解决办法
1577
查看次数