簡體   English   中英

為什么是`函數<void (string)> ` 和 ` 函數<string (string)> ` 參數類型有時會因為重載而模棱兩可?</string></void>

[英]Why are `function<void (string)>` and `function<string (string)>` parameter types sometimes ambiguous for overloading?

跟進我的問題c++ - 使用中間類型時隱式轉換如何工作? ,從中我了解了1 隱式轉換 max的規則,我試圖了解涉及 function arguments 的更高級用例。

假設我有一個 function,它接受另一個 function 作為參數。 該 function 參數可以返回某些內容,也可以不返回任何內容(無效)。 因此,我想重載 function 定義,在一種情況下接受非 void function 參數,在另一種情況下接受 void function 參數。

using VoidType = void (string);
using NonVoidType = string (string);

string call(VoidType *fn, string arg) {
    cout << "[using void function]" << endl;
    fn(arg);
    return arg;
}

string call(NonVoidType *fn, string arg) {
    cout << "[using non void function]" << endl;
    return fn(arg);
}

當調用 function 時,給定的參數具有已知類型,因此重載選擇應該很簡單,例如這里:

void printVoid(string message) {
    cout << message << endl;
}

string printNonVoid(string message) {
    cout << message << endl;
    return message;
}

void test() {
    call(printVoid, "call(printVoid)");
    call(printNonVoid, "call(printNonVoid)");
}

但這不是當我有中間類型時,例如std::function包裝器:

string call(function<VoidType> fn, string arg) {
    cout << "[using void function]" << endl;
    fn(arg);
    return arg;
}

string call(function<NonVoidType> fn, string arg) {
    cout << "[using non void function]" << endl;
    return fn(arg);
}

void test() {
    call(printVoid, "call(printVoid)");
    call(printNonVoid, "call(printNonVoid)"); // more than one instance of overloaded function "call" matches the argument list:C/C++(308)
}

為此,我得到的錯誤more than one instance of overloaded function "call" matches the argument list:C/C++(308)

對此的解決方案是在調用之前顯式實例化std::function

void test() {
    call(function(printNonVoid), "call(function(printNonVoid))");
}

但是, call(function(printNonVoid), "xxx")call(printNonVoid, "xxx")有什么不同,知道在后一種情況下,我希望隱式轉換與前一種情況下所做的相同.

我是否遺漏了一些東西,比如一些中間的、隱藏的復制構造函數或其他什么?

完整示例:

#include <iostream>

using namespace std;

using VoidType = void (string);
using NonVoidType = string (string);

string callFromPointer(VoidType *fn, string arg) {
    cout << "[callFromPointer] void" << endl;
    fn(arg);
    return "<void>";
}

string callFromPointer(NonVoidType *fn, string arg) {
    cout << "[callFromPointer] non void" << endl;
    return fn(arg);
}

string callFromFunction(function<VoidType> fn, string arg) {
    cout << "[callFromFunction] void" << endl;
    fn(arg);
    return "<void>";
}

string callFromFunction(function<NonVoidType> fn, string arg) {
    cout << "[callFromFunction] non void" << endl;
    return fn(arg);
}

void printVoid(string message) { cout << "\t[printVoid] " << message << endl; }
string printNonVoid(string message) {
    cout << "\t[printNonVoid] " << message << endl;
    return message;
}

void sep() { cout << "\n----\n" << endl; }

void main() {
    callFromPointer(printVoid, "callFromPointer(printVoid)");
    callFromPointer(printNonVoid, "callFromPointer(printNonVoid)");

    sep();

    callFromFunction(printVoid, "callFromFunction(printVoid)");
    callFromFunction(printNonVoid, "callFromFunction(printNonVoid)"); // more than one instance of overloaded function "callFromFunction" matches the argument list:C/C++(308)
    
    sep();

    callFromFunction(function(printVoid), "callFromFunction(function(printVoid))");
    callFromFunction(function(printNonVoid), "callFromFunction(function(printNonVoid))");
}

這是因為std::string(*)(std::string)std::function<void(std::string)>std::function<std::string(std::string)> string) “兼容” std::function<std::string(std::string)>因為前者可以簡單地忽略底層函數的返回值。

也就是說,以下兩個都是有效的:

std::function<void(std::string)> voidFunc(printNonVoid);
std::function<std::string(std::string)> strFunc(printNonVoid);

由於兩者都不是“更好”的匹配,因此調用callFromFunction(printNonVoid, "...")時重載解析失敗。


它在使用std::function(printNonVoid)時起作用的原因是因為 class 模板參數推導接管了,並且有一個T(*)(Args...) -> std::function<T(Args...)> . 該演繹指南將std::function(printNonVoid)變成std::function<std::string(std::string)>(printNonVoid) 因為這是一個完全匹配,不需要轉換std::function<std::string(std::string)> callFromFunction的重載,重載是由重載決議選擇的。

That deduction guide doesn't come into play when performing overload resolution with just the raw function name though, since the function arguments have to explicitly declare std::function 's template argument.

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM