Khấu trừ đối số mẫu cho một đối số của loại hàm


10

Hãy xem xét chương trình sau đây.

#include <iostream>

template <typename T>
void f( void ( *fn )( T ) )
{
    fn( 42 );
}

void g( int x )
{
    std::cout << "g( " << x << " );\n";
}

int main()
{
    f( g );
}

Chương trình biên dịch thành công và đầu ra của nó là

g( 42 );

Bây giờ hãy đổi tên hàm phi mẫu gthành f.

#include <iostream>

template <typename T>
void f( void ( *fn )( T ) )
{
    fn( 42 );
}

void f( int x )
{
    std::cout << "f( " << x << " );\n"; 
}

int main()
{
    f( f );
}

Bây giờ chương trình không được biên dịch bởi gcc HEAD 10.0.0 20200 và clang HEAD 10.0.0 nhưng được biên dịch thành công bởi Visual C ++ 2019 ..

Ví dụ, trình biên dịch gcc phát hành tập hợp các thông báo sau.

prog.cc: In function 'int main()':
prog.cc:22:10: error: no matching function for call to 'f(<unresolved overloaded function type>)'
   22 |     f( f );
      |          ^
prog.cc:4:6: note: candidate: 'template<class T> void f(void (*)(T))'
    4 | void f( void ( *fn )( T ) )
      |      ^
prog.cc:4:6: note:   template argument deduction/substitution failed:
prog.cc:22:10: note:   couldn't deduce template parameter 'T'
   22 |     f( f );
      |          ^
prog.cc:14:6: note: candidate: 'void f(int)'
   14 | void f( int x )
      |      ^
prog.cc:14:13: note:   no known conversion for argument 1 from '<unresolved overloaded function type>' to 'int'
   14 | void f( int x )
      |         ~~~~^

Vì vậy, một câu hỏi được đặt ra: mã có nên được biên dịch không và lý do nào khiến mã không được biên dịch bởi gcc và clang?



Lưu ý: trong ví dụ đầu tiên, việc truyền g(thay vì &g) cho mẫu hàm gây ra sự phân rã kiểu (một tham chiếu giá trị hàm phân rã thành một con trỏ tới hàm: void(&)(T)=> void(*)(T)). Sự hội tụ ngầm này xảy ra bởi vì không có sự fquá tải nào khác với một kết hợp tốt hơn. Trong ví dụ thứ hai, có một sự mơ hồ mà fbạn thực sự muốn gọi bởi vì ... nó cũng không biết đó flà đối số nào.
Xeverous

Câu trả lời:


7

Dường như với tôi rằng gcc và clang là chính xác. Điều này không nên biên dịch. Tham số hàm mà bạn muốn Tsuy ra trở thành bối cảnh không suy diễn ở đây tại thời điểm đối số được cung cấp là một tập hợp quá tải có chứa mẫu hàm [temp.deduct.type] /5.5 :

Các bối cảnh không suy diễn là:

  • [Càng]
  • Không thể thực hiện tham số chức năng cho phép khấu trừ đối số vì đối số chức năng được liên kết là một hàm hoặc một tập hợp các hàm bị quá tải ([over.over]) và một hoặc nhiều điều sau đây được áp dụng:

    • [Càng]
    • tập hợp các hàm được cung cấp dưới dạng đối số chứa một hoặc nhiều mẫu hàm.
  • [Càng]

Do đó, Tkhông thể suy ra và tình trạng quá tải khác là không khả thi do không có chuyển đổi; chính xác những gì gcc nói


0

Đây là hai hàm bị quá tải và hàm không phải là khuôn mẫu nên được chọn so với hàm templated, vì vậy f (int x) đã được chọn do đó việc truyền một hàm làm đối số trong hàm mà int phải truyền là không thể. và dưới đây nên làm việc. Cảm ơn

void f( void ( *fn )( int ) ){
  fn( 42 );
}
void f( int x ){
    std::cout << "f( " << x << " );\n";
  }

  int main(){

     f( f );
  }

Các chức năng không phải mẫu chỉ được ưu tiên khi có sự ràng buộc trong quá trình giải quyết quá tải. Mã của câu hỏi không đi đến điểm đó: không bao giờ có chuyên môn void f<int>(void(int))được tạo để thực hiện giải quyết quá tải ở cả hai cấp độ.
Davis Herring
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.