标签: overload-resolution

当需要用户定义的转换时,左值和右值引用参数之间的重载解析

考虑以下代码:

#include <cstdio>
struct S {
    S(int) {}
};
void f(const S&) { std::puts("const S&"); }
void f(S&&) { std::puts("S&&"); }
int main() {
    f(42);
}
Run Code Online (Sandbox Code Playgroud)

很明显,GCC 和 Clang 都同意应该调用重载S&&,但我对标准的解读是,实际上没有规则要求这种情况!

当然,您会说调用f必须初始化一个临时S对象,并且重载解析更喜欢将右值引用绑定到右值而不是绑定左值引用。然而,这就是标准在 [over.ics.rank]/(3.2) 中实际所说的内容:

标准转换序列S1是比标准转换序列更好的转换序列,S2如果

...

  • S1S2是引用绑定 (11.6.3),两者都不引用未使用ref-qualifier声明的非静态成员函数的隐式对象参数,并且S1将右值引用绑定到右值并S2绑定左值引用

...

因此,有关左值和右值引用绑定的决胜局仅适用于标准转换序列。但是需要用户定义的f转换序列才能调用给定int参数的任一重载。用户自定义转换序列的排序规则为(3.3),

如果用户定义的转换序列U1包含相同的用户定义的转换函数或构造函数,或者它们在聚合初始化中初始化相同的类,并且在这两种情况下,第二个标准转换序列是,则用户定义的转换序列是U2比另一个用户定义的转换序列更好的转换序列U1优于 的第二个标准转换序列U2

显然,两个转换序列(toconst …

c++ overload-resolution

5
推荐指数
0
解决办法
94
查看次数

重载 operator delete 而不重载 new 时的正确行为是什么?gcc 和 clang 不同

以下代码与clang(x86_64-pc-linux-gnu 上的版本 5.0.0-3~16.04.1)和gcc (9.2.0) 的行为不同。

void operator delete(void* ptr) noexcept {
    std::cout << "overloaded delete" << std::endl;
    free(ptr);
}

int main() {
    int* pint = new int;
    delete pint; // clang doesn't go through overloaded operator delete, gcc does
}
Run Code Online (Sandbox Code Playgroud)

gcc通过重载,operator deleteclang避免它更喜欢global delete.

(当添加重载时,operator new两个编译器都同意并通过两个重载版本)。

代码:http : //coliru.stacked-crooked.com/a/0903bd53a8c04a9b

c++ gcc operator-overloading clang overload-resolution

5
推荐指数
1
解决办法
80
查看次数

Java静态多态(重载)和泛型之间的继承

Java 11(可能无关紧要):

public static String toString(Object obj) {
    return ReflectionToStringBuilder.toString(obj, ToStringStyle.SHORT_PREFIX_STYLE);
}

public static String toString(Collection<Object> collection) {
    return collection.stream()
            .map(SaLogUtils::toString)
            .collect(Collectors.joining(", ", "[", "]"));
}

public static void main(String[] args) {
    List<Integer> list = List.of(Integer.valueOf(1));
    System.out.println(SaLogUtils.toString(list));
    System.out.println(SaLogUtils.toString(List.of(Integer.valueOf(1))));
}
Run Code Online (Sandbox Code Playgroud)

令人惊讶的输出:

// from toString(Object)
ImmutableCollections.List12[e0=1,e1=<null>]
// from toString(Collection<Object>)
[Integer[value=1]]
Run Code Online (Sandbox Code Playgroud)

为什么Java静态选择不同的方法?

java generics overload-resolution static-polymorphism java-11

5
推荐指数
1
解决办法
94
查看次数

为什么重载决议选择指针类型为 0 而不是 1,在任何一种情况下它都可以选择省略号?

我有以下代码片段:

void eval(void*) { std::cout << "hello world\n"; }
void eval(...) { }
int main(int argc, char *argv[])
{
    std::cout << "0: "; eval(0);
    std::cout << "1: "; eval(1);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这给出了输出:

0: hello world
1: 
Run Code Online (Sandbox Code Playgroud)

我的问题是:为什么重载解析选择的void*版本eval而不是...for的版本0,而不是 for 1?似乎在这两种情况下,它都可以推断出参数是一个 int 并采用可变参数版本。

c++ overloading overload-resolution

5
推荐指数
1
解决办法
79
查看次数

使用隐式转换重载解析

我基本上想要 string/FormattableString 的两个单独的重载(背景是我想推动人们使用字符串常量来记录日志消息并通过结构化日志而不是日志消息传递参数以简化分析。因此 FormattableString 日志记录方法将被废弃)。

现在由于编译器的工作方式,您不能直接重载方法,因为 FormattableString 在传递之前会转化为字符串。但有效的是有一个定义隐式重载的包装结构:

public struct StringIfNotFormattableStringAdapter
{
    public string StringValue { get; }

    private StringIfNotFormattableStringAdapter(string s)
    {
        StringValue = s;
    }

    public static implicit operator StringIfNotFormattableStringAdapter(string s)
    {
        return new StringIfNotFormattableStringAdapter(s);
    }

    public static implicit operator StringIfNotFormattableStringAdapter(FormattableString fs)
    {
        throw new InvalidOperationException("This only exists to allow correct overload resolution. " +
                                            "This should never be called since the FormattableString overload should be preferred to this.");
    }
}

public static class Test
{
    public static void …
Run Code Online (Sandbox Code Playgroud)

c# language-lawyer overload-resolution

5
推荐指数
1
解决办法
219
查看次数

带有两个(或更多)特定包(专业化/重载)的可变参数函数模板

函数“Process”正在接受可变数量的变量类型参数。为了处理不同的情况,我已经成功地像这样重载了它:

// general case
template <typename ...Types>
void Process( const Types&... items )

// single T
template <typename T>
void Process( const T& t )

// one or more of type NVP<>
template <typename T1, typename ...Types>
void Process( const NVP<T1>& nvp1, const NVP<Types>&... nvps )
Run Code Online (Sandbox Code Playgroud)

我想要做的 - 但不能 - 如下:对于具有任意数量的类型的前导参数ATT<>后跟任意数量的情况,我需要重载NVP<>

// any number of leading Types ATT<> followed by any number of NVP<>
template <typename ...ATypes, typename ...BTypes>
void Process( const ATT<ATypes>&... …
Run Code Online (Sandbox Code Playgroud)

c++ variadic-functions overload-resolution variadic-templates c++17

5
推荐指数
1
解决办法
192
查看次数

Swift:为函数类型专门化泛型类的方法

对于通用自由函数,我可以使用重载,从本质上将函数专门化为函数类型,如下所示:

func foo<T>(_ t: T.Type) { print("T is unknown") }
func foo<P>(_ t: ((P) -> Void).Type) { print("T is a function with one parameter") }

let f: (String) -> Void = { print($0) }    
foo(type(of: f))   //  prints "T is a function with one parameter"
Run Code Online (Sandbox Code Playgroud)

注意第二个版本foo()不受协议约束的,主要是因为据我所知,我们不能让函数类型符合协议(我们不能扩展非名义类型)。我可以创建一个OneParamFunction协议,并且可以在一个受约束的 中使用它foo(),但是我不能让所有的单参数函数类型都符合那个协议。

但是上述重载在没有协议约束的情况下工作。

对于泛型类的实例方法,这样的事情可能吗?

对我来说,这种语法似乎是最自然的,但它不受支持:

class Generic1<T> { init(_ t: T.Type) {} }
extension Generic1 { func foo() { print("T is unknown") } }

extension Generic1<P>
    where …
Run Code Online (Sandbox Code Playgroud)

generics overload-resolution swift

5
推荐指数
1
解决办法
519
查看次数

当泛型类型绑定到 Any 时,kotlin 重载解析歧义

考虑这段代码

fun main() {
    class A<T> {
        fun m(t: T): Unit {
            print("T")
        }
        fun m(t: List<T>): Unit {
            print("List<T>")
        }
    }
    
    val a: A<Any> = A()
    val l: List<Any> = listOf()
    a.m(l)
}
Run Code Online (Sandbox Code Playgroud)

a.m(l)调用似乎不明确,并出现以下错误:

重载解析歧义: public final fun m(t: Any): main.A 中定义的单位 public final fun m(t: List<Any>): main.A 中定义的单位

我的直觉告诉我,m(t: List<T>)重载应该更具体,但我的直觉已经错误了一次,当时我在 Java 中遇到过类似的情况

我可以这样称呼“错误”的重载:

a.m(l as Any)
Run Code Online (Sandbox Code Playgroud)

但是我怎样才能明确地调用所需的m(t: List<T>)重载呢?铸造a.m(l as List<Any>)不起作用。

generics overload-resolution kotlin

5
推荐指数
1
解决办法
858
查看次数

当派生类方法不可行时,为什么 C++ 重载决策不查看基类方法?

编译失败的例子:

class A{
 public:
  int f(int a) {return a;}
};

class B: public A {
 public:
  int f(int a, int b) {return a + b;}
};

int calculation(int num) {
    B b;
    return b.f(num);
}
Run Code Online (Sandbox Code Playgroud)

在调用站点b.f(num)gcc给出以下错误消息:

错误:没有匹配的函数可供调用B::f(int&)

基类有一个可行的候选者,但由于某种原因编译器不会考虑它。

如果我将调用重写为b.A::f(num),那么它就可以正常工作。我不明白为什么这A::是必要的。为什么 的A::f重载解析逻辑不将其视为可行的候选者b.f

c++ inheritance overload-resolution

5
推荐指数
2
解决办法
369
查看次数

来自 initalizer_list 的构造函数和来自需要转换的值的构造函数之间的重载解析,编译器存在分歧

在下面的代码中,struct A有两个构造函数:A(int)A(std::initializer_list<char>)。然后使用以下命令创建该结构的对象A({0})

#include <initializer_list>

struct A {
    int a;
    constexpr A(int) { a = 1; } 
    constexpr A(std::initializer_list<char>) { a = 2; }
};

static_assert( A({0}).a == 2 );
Run Code Online (Sandbox Code Playgroud)

事实证明,GCC 和 Clang 更喜欢这里的构造函数initializer_list(尽管int必须在 中转换参数char)并且整个程序被接受,但 MSVC 选择A(int)构造函数,导致static_assert. 演示: https: //gcc.godbolt.org/z/qx7W417Mv

这里是哪个编译器?

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

5
推荐指数
1
解决办法
89
查看次数