标签: overload-resolution

如何用文字0和指针解决对重载函数的调用歧义

我很确定这一定已经在这里了,但是我没有找到很多关于如何解决这类问题的信息(没有在电话上强制转换):

给定两个重载,我希望一个带有文字0的函数的调用总是调用unsigned int版本:

void func( unsigned int ) {
    cout << "unsigned int" << endl;
}

void func( void * ) {
    cout << "void *" << endl;
}

func( 0 ); // error: ambiguous call
Run Code Online (Sandbox Code Playgroud)

我明白为什么会这样,但我不想一直写func(0u)甚至func(static_cast(0)).所以我的问题是:

1)是否有推荐的方法来执行此操作?

2)以下方式进行操作是否有任何问题,这是什么原因?

void func( unsigned int ) {
    cout << "unsigned int" << endl;
}

template <typename T>
void func( T * ) {
    static_assert( std::is_same<T, void>::value, "only void pointers allowed" );
    cout << "void *" << endl;
}

func( 0 ); // …
Run Code Online (Sandbox Code Playgroud)

c++ templates overloading overload-resolution

10
推荐指数
1
解决办法
6546
查看次数

成员函数隐藏自由函数

void foo(int)
{
}

class X
{
    void foo()
    {
    }

    void bar()
    {
        foo(42);
        // error: no matching function for call to 'X::foo(int)'
        // note: candidate is:
        // note: void X::foo()
        // note:   candidate expects 0 arguments, 1 provided        
    }
};
Run Code Online (Sandbox Code Playgroud)

为什么C++无法调用自由函数(这是唯一具有正确签名的函数)?

c++ visibility function overload-resolution

10
推荐指数
2
解决办法
956
查看次数

运算符如何在名称空间中重载解析?

我发现C++解析运算符重载的奇怪行为,我无法解释自己.指向描述它的某个资源的指针就像答案一样好.

我有2个翻译单位.在一个(称为util.cpp/h)中,我声明并定义了两个运算符(我省略了readabilty的实际实现,无论如何都会发生problam):

// util.h
#ifndef GUARD_UTIL
#define GUARD_UTIL

#include <iostream>

std::istream& operator>>(std::istream& is, const char* str);
std::istream& operator>>(std::istream& is, char* str);
#endif
Run Code Online (Sandbox Code Playgroud)

和:

//util.cpp
#include "util.h"
#include <iostream>

std::istream& operator>>(std::istream& is, const char* str) {
  return is;  
}
std::istream& operator>>(std::istream& is, char* str) {
  return is;  
}
Run Code Online (Sandbox Code Playgroud)

如果在全局命名空间中,这些运算符是因为它们在std类型和内置类型上运行,并且应该可以在任何地方使用.它们只能从全局命名空间(例如来自main())或明确地告诉编译器它们在全局命名空间中工作(参见代码示例).

在另一个翻译单元(称为test.cpp/h)中,我在命名空间中使用这些运算符.这有效,直到我将类似的运算符放入此命名空间.一旦添加此运算符,编译器(例如gcc或clang)就不能再找到可行的运算符>>.

// test.h
#ifndef GUARD_TEST
#define GUARD_TEST

#include <iostream>

namespace Namespace {
  class SomeClass {   
    public:
      void test(std::istream& is);
  };

  // without the following line everything compiles just fine
  std::istream& operator>>(std::istream& is, …
Run Code Online (Sandbox Code Playgroud)

c++ operators overload-resolution

10
推荐指数
1
解决办法
3564
查看次数

Lambda转换具有不明确的返回类型和重载决策

如果我有一个像() => { throw new Exception(); }这样的lambda ,则不清楚它是否有返回类型.因此,它可以(隐式)转换为ActionFunc<object>(或任何其他Func<T>).这是因为,根据§6.5C #4规范的匿名函数转换:

[A]委托类型D与提供的匿名功能兼容F:

  • ...

  • 如果D有一个void返回类型且body F是一个语句块,当[...]的主体F是一个有效的语句块时,其中没有return语句指定一个表达式.

  • 如果D具有非void返回类型且body F是一个语句块,则当[...]主体F是具有不可到达端点的有效语句块时,其中每个return语句指定一个可隐式转换为返回的表达式的类型D.

但是如果我有一个方法的两个重载,其中一个具有类型的参数Action和另一个Func<object>,并且我从上面传递lambda,Func<object>则使用重载.为什么?规范的哪一部分说Func<object>Action这种情况更好?

我已经看过§7.5.3.2 更好的函数成员,但这并没有解释它.

c# lambda overload-resolution

10
推荐指数
1
解决办法
341
查看次数

为什么第一个函数调用绑定到第一个函数?

为什么第一个函数call(cm(car);)绑定到第一个函数?

我知道第二个调用绑定到第二个函数,因为它是非模板,尽管两者都是完美的匹配.

如果第一个函数被定义为具有固定数组长度的非模板,则:

    void cm(const char (&h)[8]) {cout << "const char (&)[8]" << endl;}
Run Code Online (Sandbox Code Playgroud)

而不是它再次被选中在第二个(第二个调用将是不明确的那种方式).

码:

template<size_t N> void cm(const char (&h)[N]) 
    {std::cout << " const (&)[N] " << endl;}

void cm(const char * h)
    {cout << " const char * " << endl;}

int main()
{
    char car[] = "errqweq";
    const char ccar[] = "errqweq";
    cm(car);
    cm(ccar);
}
Run Code Online (Sandbox Code Playgroud)

输出:

 const (&)[N]
 const char * 
Run Code Online (Sandbox Code Playgroud)

c++ templates function language-lawyer overload-resolution

10
推荐指数
1
解决办法
153
查看次数

显式构造函数和嵌套初始化列表

以下代码成功编译了大多数现代C++ 11兼容编译器(GCC> = 5.x,Clang,ICC,MSVC).

#include <string>

struct A
{
        explicit A(const char *) {}
        A(std::string) {}
};

struct B
{
        B(A) {}
        B(B &) = delete;
};

int main( void )
{
        B b1({{{"test"}}});
}
Run Code Online (Sandbox Code Playgroud)

但是为什么它首先编译,以及列出的编译器如何解释该代码?

为什么MSVC能够在没有的情况下编译它B(B &) = delete;,但其他3个编译器都需要它?

为什么在删除复制构造函数的不同签名时,除了MSVC之外的所有编译器都会失败,例如B(const B &) = delete;

编译器甚至都选择相同的构造函数吗?

为什么Clang会发出以下警告?

17 : <source>:17:16: warning: braces around scalar initializer [-Wbraced-scalar-init]
        B b1({{{"test"}}});
Run Code Online (Sandbox Code Playgroud)

c++ overload-resolution c++11 list-initialization

10
推荐指数
1
解决办法
1130
查看次数

为什么派生类返回类型的显式转换函数不是直接初始化上下文中的候选函数

给出以下示例:

#include <iostream>
struct A{
    A() = default;
    A(A const&){}
};
struct B:A{};
struct C{
    explicit operator B(){
        return B{};
    }
};

int main(){
   C c;
   A a(c);  // #1
}
Run Code Online (Sandbox Code Playgroud)

GCCClang两个报告c都不能转换为const A&. 但是,标准中有一条相关规则说,explicit operator B()在这种情况下应该是候选函数。即:
over.match.copy#1.2

当初始化一个临时绑定到构造函数的第一个参数时,该参数的类型是“对可能有 cv 限定的 T 的引用”,并且在直接初始化类型对象的上下文中使用单个参数调用构造函数时“cv2 T”,也考虑了显式转换函数。那些没有隐藏在 S 中并且产生其 cv 非限定版本与 T 类型相同的类型或其派生类的类型是候选函数

而且,在现行标准中,相关规则的含义仍然相同:
over.match.copy#1.2

当初始化表达式的类型是类类型“cv S”时,考虑转换函数。非显式转换函数的允许类型是T 和从 T 派生的任何类初始化临时对象 ([class.mem]) 以绑定到构造函数的第一个参数时,其中该参数的类型为“对 cv2 T 的引用”,并且在直接初始化的上下文中使用单个参数调用构造函数对于“cv3 T”类型的对象,显式转换函数的允许类型是相同的 …

c++ language-lawyer overload-resolution

9
推荐指数
0
解决办法
220
查看次数

std::initializer_list 中两个构造函数之间的重载解析

在下面的程序中,structC有两个构造函数:一个来自std::initializer_list<A>,另一个来自std::initializer_list<B>。然后使用以下命令创建该结构的对象C{{1}}

#include <initializer_list>

struct A {
    int i;
};

struct B {
    constexpr explicit B(int) {}
};

struct C {
    int v;
    constexpr C(std::initializer_list<A>) : v(1) {}
    constexpr C(std::initializer_list<B>) : v(2) {}
};

static_assert( C{{1}}.v == 1 );
Run Code Online (Sandbox Code Playgroud)

由于只能A从 隐式构造聚合int,因此可以预期这C(std::initializer_list<A>)是首选并且程序成功。在 Clang 中确实如此。

然而海湾合作委员会抱怨:

error: call of overloaded 'C(<brace-enclosed initializer list>)' is ambiguous
note: candidate: 'constexpr C::C(std::initializer_list<B>)'
note: candidate: 'constexpr C::C(std::initializer_list<A>)'
Run Code Online (Sandbox Code Playgroud)

MSVC 也是如此:

error C2440: '<function-style-cast>': cannot …
Run Code Online (Sandbox Code Playgroud)

c++ initializer-list language-lawyer overload-resolution

9
推荐指数
1
解决办法
190
查看次数

C++ 中转换运算符到值和常量引用之间的重载解析

在下面的程序中 structB定义了两个转换运算符: toA和 to const A&。然后A从 -object 创建B-object:

struct A {};

struct B {
  A a;
  B() = default;
  operator const A&() { return a; }
  operator A() { return a; }
};

int main() {
  (void) A(B{});
}
Run Code Online (Sandbox Code Playgroud)

该计划是

  • MSVC 接受所有语言版本。
  • 所有语言版本均被 GCC 拒绝。
  • 在 C++14 模式下被 Clang 拒绝,在 C++17 模式下被接受。演示: https: //gcc.godbolt.org/z/rKv589EG3

GCC 错误消息是

error: call of overloaded 'A(B)' is ambiguous
note: candidate: 'constexpr A::A(const A&)'
note: candidate: 'constexpr …
Run Code Online (Sandbox Code Playgroud)

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

9
推荐指数
1
解决办法
179
查看次数

具有自动非类型模板参数的函数模板的重载解析

如果参数之一是占位符类型,则在非类型模板参数的情况下选择重载函数模板的规则是什么。我对编译器当前的行为感到困惑,请考虑下一个示例:

template<int N> struct A{};

template<auto... N> void f(A<N...>);
template<int N>     void f(A<N>) {}

template<auto N>    void g(A<N>);
template<int N>     void g(A<N>) {}

int main() {
    f( A<1>{} ); // ok in GCC and Clang, error in MSVC
    g( A<1>{} ); // ok in GCC, error in Clang and MSVC
}
Run Code Online (Sandbox Code Playgroud)

这里 MSVC 无法在两组重载之间进行选择。另一方面,GCC总是选择类型更具体的函数模板<int>。Clang 有点处于中间位置,它<int>比参数 pack 更受欢迎,但它在和重载<auto...>之间的选择过程中发现了歧义。在线演示: https: //gcc.godbolt.org/z/4EK99Gjhx<int><auto>

哪一项行为是正确的或者标准没有明确规定?

c++ templates partial-ordering language-lawyer overload-resolution

9
推荐指数
1
解决办法
237
查看次数