标签: overload-resolution

两个函数模板何时被视为部分有序且何时不明确?

在阅读了如何使这些std :: function参数明确无误后,我完全糊涂了到目前为止,我认为我理解函数模板的部分排序是什么,但在阅读了这个问题后,我写了三个例子来检查编译器的行为,并且收到的结果很难让我理解.

示例#1

template <class T>
void foo(T) {}

template <class T>
void foo(T&) {}

int main()
{
  int i;
  foo<int>(i); // error: call is ambiguous! 
}
Run Code Online (Sandbox Code Playgroud)

问题:这两个功能都是可行的,这是显而易见的,但不是那个T&比专业更专业的功能T?相反,编译器会引发模糊的调用错误.

例#2

#include <iostream>

template <class T>
struct X {};

template <>
struct X<int> 
{
  X() {}
  X(X<int&> const&) {} // X<int> is constructible from X<int&>
  // note: this is not a copy constructor!
};

template <>
struct X<int&> …
Run Code Online (Sandbox Code Playgroud)

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

11
推荐指数
1
解决办法
304
查看次数

内置运算符 == 重载的解析

在以下代码中,struct A有两个隐式转换运算符到charint,并且将结构体的实例与整数常量进行比较2

struct A {
    constexpr operator char() { return 1; }
    constexpr operator int() { return 2; }
};
static_assert( A{} == 2 );
Run Code Online (Sandbox Code Playgroud)

代码在 GCC 和 MSVC 中顺利通过,但 Clang 抱怨:

<source>:5:20: error: use of overloaded operator '==' is ambiguous (with operand types 'A' and 'int')
static_assert( A{} == 2 );
               ~~~ ^  ~
<source>:5:20: note: because of ambiguity in conversion of 'A' to 'float'
<source>:2:15: note: candidate function
    constexpr operator …
Run Code Online (Sandbox Code Playgroud)

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

11
推荐指数
1
解决办法
391
查看次数

如何用文字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
查看次数

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

为什么第一个函数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
查看次数

为什么可变参数模板构造函数比复制构造函数更好?

以下代码无法编译:

#include <iostream>
#include <utility>

struct Foo
{
    Foo() { std::cout << "Foo()" << std::endl; }
    Foo(int) { std::cout << "Foo(int)" << std::endl; }
};

template <typename T>
struct Bar
{
    Foo foo;

    Bar(const Bar&) { std::cout << "Bar(const Bar&)" << std::endl; }

    template <typename... Args>
    Bar(Args&&... args) : foo(std::forward<Args>(args)...)
    {
        std::cout << "Bar(Args&&... args)" << std::endl;
    }
};

int main()
{
    Bar<Foo> bar1{};
    Bar<Foo> bar2{bar1};
}
Run Code Online (Sandbox Code Playgroud)

编译器错误告诉我编译器试图使用variadic模板构造函数而不是复制构造函数:

prog.cpp: In instantiation of 'Bar<T>::Bar(Args&& ...) [with Args = {Bar<Foo>&}; T = …
Run Code Online (Sandbox Code Playgroud)

c++ templates overload-resolution variadic-templates c++11

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

Kotlin:内联lambda和重载分辨率模糊

我有一个简单的工厂模式,其中的实现是通过重载决定来确定的.问题是Kotlin编译器抱怨内联lambda的"Overload resolution ambiguity ..".

class Foo(){
    companion object Factory {
        fun create(x: Int, f: (Int) -> Double) = 2.0
        fun create(x: Int, f: (Int) -> Int) = 1
    }
}

fun main(args:Array<String>){
    val a =  Foo.create(1,::fromDouble) //OK
    val b =  Foo.create(1,::fromInt)  //OK
    val ambiguous =  Foo.create(1){i -> 1.0}  //Overload resolution ambiguity?
}


fun fromDouble(int:Int)  = 1.0
fun fromInt(int:Int)  = 1
Run Code Online (Sandbox Code Playgroud)

Kotlin编译器如何解决重载解析,为什么内联lambda被认为是不明确的?

lambda overload-resolution kotlin

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

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

以下代码成功编译了大多数现代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
查看次数

数组引用绑定与使用模板的数组到指针转换

由于重载解析不明确,此代码示例无法编译

void g(char (&t)[4]) {}
void g(char *t) {}

int main()
{
  char a[] = "123";
  g(a);
}
Run Code Online (Sandbox Code Playgroud)

仔细阅读重载解析规则可以清楚为什么失败。这里没有问题。

如果我们正式将其改造为模板版本

template <typename T> void g(T (&t)[4]) {}
template <typename T> void g(T *t) {}

int main()
{
  char a[] = "123";
  g(a);
}
Run Code Online (Sandbox Code Playgroud)

它将继续“按预期”运行,并因同样性质的模糊性而失败。到目前为止,一切都很好。

然而,下面的版本编译没有任何问题并选择了第二个重载

template <typename T> void g(T &t) {}
template <typename T> void g(T *t) {}

int main()
{
  char a[] = "123";
  g(a);
}
Run Code Online (Sandbox Code Playgroud)

如果我们注释掉第二个重载,第一个重载将成功地与推导为T一起使用char [4],即模板参数推导按第一个版本的预期工作,有效地使其相当于void g(char (&t)[4])。因此,乍一看,第三个示例的行为应该与前两个示例相同。

然而,它可以编译。在第三种情况下,什么[模板]重载解析规则可以挽救局面并指示编译器选择第二个重载?为什么它更喜欢数组到指针的转换而不是直接引用绑定?

PS …

c++ arrays templates overload-resolution

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