Tại sao mẫu hàm không thể chuyên biệt một phần?


87

Tôi biết đặc tả ngôn ngữ cấm chuyên môn hóa từng phần của mẫu hàm.

Tôi muốn biết lý do tại sao nó cấm nó? Chúng không hữu ích?

template<typename T, typename U> void f() {}   //allowed!
template<> void f<int, char>()            {}   //allowed!
template<typename T> void f<char, T>()    {}   //not allowed!
template<typename T> void f<T, int>()     {}   //not allowed!

Đối với template<typename T, typename U> void f(T t, U u) {}cũng template<> void f(int t, char u) {}được cho phép.
thoáng qua

10
Tôi thấy thật thú vị khi mọi người tiếp tục đưa ra các giải pháp thay thế khi câu hỏi không phải là "làm thế nào tôi có thể đạt được một mục tiêu tương tự" mà là "lý do đằng sau hành vi này là gì" ... Bản thân tôi không biết lý do của sự lựa chọn này, nhưng tôi cho rằng Ủy ban phải có lý do để cấm chuyên môn hóa từng phần của mẫu chức năng. Cho đến nay, lời giải thích "gần nhất" là liên kết được đăng bởi Georgy, chỉ chỉ ra những "rủi ro" tiềm ẩn của việc chuyên môn hóa từng phần của mẫu chức năng khi có hiện tượng quá tải. Tuy nhiên, tôi không nghĩ rằng đó là một lý do để cấm tính năng này, vì vậy tôi giả sử có nhiều đến thế này ..
bartgol

Câu trả lời:


59

AFAIK đã được thay đổi trong C ++ 0x.

Tôi đoán đó chỉ là một sự giám sát (xem xét rằng bạn luôn có thể nhận được hiệu ứng chuyên môn hóa từng phần với nhiều mã dài dòng hơn, bằng cách đặt hàm như một staticthành viên của một lớp).

Bạn có thể tra cứu DR (Báo cáo lỗi) có liên quan, nếu có.

CHỈNH SỬA : kiểm tra điều này, tôi thấy rằng những người khác cũng đã tin vào điều đó, nhưng không ai có thể tìm thấy bất kỳ hỗ trợ nào như vậy trong tiêu chuẩn dự thảo. Chủ đề SO này dường như chỉ ra rằng chuyên môn hóa một phần của các mẫu hàm không được hỗ trợ trong C ++ 0x .

CHỈNH SỬA 2 : chỉ là một ví dụ về ý của tôi khi "đặt hàm như một staticthành viên của một lớp":

#include <iostream>
using namespace std;

// template<typename T, typename U> void f() {}   //allowed!
// template<> void f<int, char>()            {}   //allowed!
// template<typename T> void f<char, T>()    {}   //not allowed!
// template<typename T> void f<T, int>()     {}   //not allowed!

void say( char const s[] ) { std::cout << s << std::endl; }

namespace detail {
    template< class T, class U >
    struct F {
        static void impl() { say( "1. primary template" ); }
    };

    template<>
    struct F<int, char> {
        static void impl() { say( "2. <int, char> explicit specialization" ); }
    };

    template< class T >
    struct F< char, T > {
        static void impl() { say( "3. <char, T> partial specialization" ); }
    };

    template< class T >
    struct F< T, int > {
        static void impl() { say( "4. <T, int> partial specialization" ); }
    };
}  // namespace detail

template< class T, class U >
void f() { detail::F<T, U>::impl(); }    

int main() {
    f<char const*, double>();       // 1
    f<int, char>();                 // 2
    f<char, double>();              // 3
    f<double, int>();               // 4
}

bạn có tiêu chuẩn trong n3225 không? Tôi đã tìm kiếm nhanh nhưng không thể tìm thấy: /
Matthieu M.

1
à xin lỗi ... thiếu một từ. Tôi có tài liệu, nhưng không thể tìm thấy đoạn văn cụ thể . Mặc dù đã đưa ra bản chỉnh sửa của bạn, tôi đoán đơn giản là vì nó không có ở đó :)
Matthieu M.

3
Điều này không được thay đổi trong C ++ 0x. Tôi cũng nghi ngờ về tiện ích của nó. Bạn luôn có thể làm quá tải mẫu và sử dụng đặt hàng từng phần .
Johannes Schaub - litb

1
Cập nhật muộn: không thay đổi ngay cả trong C ++ 17 tám năm sau và dường như cũng không nhập C ++ 20. Không thể nhìn thấy bất kỳ lý do, mặc dù ...
Aconcagua

Tôi tin rằng đây là cách triển khai toàn diện nhất của khái niệm này
Victor

18

Chà, bạn thực sự không thể chuyên môn hóa một phần hàm / phương thức, tuy nhiên bạn có thể làm quá tải.

template <typename T, typename U>
T fun(U pObj){...}

// acts like partial specialization <T, int> AFAIK 
// (based on Modern C++ Design by Alexandrescu)
template <typename T>
T fun(int pObj){...} 

Đó là cách nhưng tôi không biết nó có làm hài lòng bạn không.


1
Chà, tâm trí của tôi tràn ngập những khuôn mẫu đến nỗi tôi thực sự quên rằng mọi thứ có thể đơn giản như thế nào :)
Johannes

1
Thật không may, đó không phải là trường hợp khi bạn muốn truyền các đối số khác nhau sau khi chuyên môn hóa một phần hàm .. :(
Gwangmu Lee

Tôi không chắc ý nghĩa của việc truyền các mẫu đa dạng, vì vậy tôi muốn biết nó khác với chuyên môn hóa một phần như thế nào. Bạn có thể vui lòng cung cấp thêm chi tiết?
beginpluses

Điều gì sẽ xảy ra nếu bạn chỉ muốn hai hàm cho tất cả các loại tích phân và phao?
Dmitriy Dokshin

14

Nói chung, không nên chuyên biệt hóa các mẫu hàm, vì những rắc rối với quá tải. Đây là một bài báo hay từ Tạp chí Người dùng C / C ++: http://www.gotw.ca/publications/mill17.htm

Và nó chứa một câu trả lời trung thực cho câu hỏi của bạn:

Có điều, bạn không thể chuyên môn hóa chúng một phần - khá nhiều chỉ vì ngôn ngữ nói rằng bạn không thể.


3
Bài báo không nói về chuyên môn hóa từng phần ngoài việc nó được đề cập một lần.
Euri Pinhollow

11

Vì bạn có thể chuyên môn hóa một phần các lớp, nên bạn có thể sử dụng một trình biểu diễn:

#include <iostream>

template < typename dtype , int k > struct fun
{
 int operator()()
 {
  return k ;
 }
} ;

template < typename dtype > struct fun < dtype , 0 >
{
 int operator()()
 {
  return 42 ;
 }
} ;

int main ( int argc , char * argv[] )
{
 std::cout << fun<float,5>()() << std::endl ;
 std::cout << fun<float,0>()() << std::endl ;
}

1
Sau đó, bạn có thể sử dụng một mẫu hàm duy nhất để thực hiện cuộc gọi, loại bỏ ()()cú pháp xấu xí .
tmr232 4/12/16
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.