2013-09-02 77 views
9

Sau khi đã tìm thấy câu trả lời cho nhiều câu hỏi của tôi trên stackoverflow, tôi bây giờ đã đưa ra một câu hỏi mà tôi không thể tìm thấy câu trả lời và tôi hy vọng rằng ai đó sẵn sàng giúp tôi!Tại sao các chuyên môn về mẫu chức năng không được phép bên trong một lớp học?

Vấn đề của tôi là tôi muốn thực hiện một biểu mẫu rõ ràng của một hàm bên trong một lớp trong C++. Trình biên dịch của tôi (g ++) và một cái nhìn trong tiêu chuẩn C++ (§14.7.3) cho tôi biết rằng chuyên môn này phải được thực hiện trong không gian tên trong đó lớp được khai báo. Tôi hiểu rằng điều này ngụ ý rằng tôi không thể đưa chuyên môn vào trong lớp, nhưng tôi không thấy điểm hạn chế này! Có ai biết nếu có lý do chính đáng để không cho phép các chuyên môn được thực hiện bên trong lớp học không?

Tôi biết rằng có nhiều giải pháp, ví dụ: để đặt hàm bên trong một cấu trúc, nhưng tôi muốn hiểu tại sao ngôn ngữ lại có thiết kế này. Nếu có lý do chính đáng để không cho phép các chức năng chuyên biệt bên trong lớp, tôi đoán tôi nên biết trước khi cố gắng giải quyết nó.

Cảm ơn trước!


Để làm cho câu hỏi của tôi chính xác hơn một chút: Đây là một số mã từ một ví dụ thử nghiệm mà minh họa những gì tôi muốn làm:

#include <cstdio> 

namespace MalinTester { 

template <size_t DIMENSIONALITY> 
class SpecializationTest { 
public: 
    SpecializationTest() { 
     privateVariable = 5; 
    }; 
    virtual ~SpecializationTest() {}; 

    void execute() { 
     execute<DIMENSIONALITY>(); 
    }; 

private: 
    int privateVariable; 
    template <size_t currentDim> 
    static void execute() { 
     printf("This is the general case. Current dim is %d. The private variable is %d.\n", currentDim, privateVariable); 
     execute<currentDim-1>(); 
    } 

    template <> 
    static void execute<0>() { 
     printf("This is the base case. Current dim is 0.\n"); 
    } 

}; 

Đây không phải là có thể; g ++ nói:

SpecializationTest_fcn.h:27: error: explicit specialization in non-namespace scope ‘class MalinTester::SpecializationTest<DIMENSIONALITY>’ 
SpecializationTest_fcn.h:28: error: template-id ‘execute<0>’ in declaration of primary template 

Nếu tôi đặt các chức năng thực thi bên ngoài lớp học, trong MalinTester tên không gian, nó sẽ giống như thế này:

#include <cstdio> 

namespace MalinTester { 

    template <size_t DIMENSIONALITY> class SpecializationTest {}; 

    template <size_t currentDim> 
    void execute() { 
     printf("This is the general case. Current dim is %d. The private variable is %d.\n", currentDim, privateVariable); 
     execute<currentDim-1>(); 
    } 

    template <> 
    void execute<0>() { 
     printf("This is the base case. Current dim is 0.\n"); 
    } 

    template <size_t DIMENSIONALITY> 
    class SpecializationTest { 
    public: 
     SpecializationTest() {}; 
     virtual ~SpecializationTest() {}; 

     void execute() { 
      MalinTester::execute<DIMENSIONALITY>(); 
     }; 
    private: 
     int privateVariable = 5; 
    }; 
}; 
}; 

và tôi không thể sử dụng privatevariable trong các phiên bản templatized của thực , vì nó là riêng tư trong lớp. Tôi thực sự muốn riêng tư, vì tôi muốn dữ liệu của mình được đóng gói càng nhiều càng tốt.

Tất nhiên tôi có thể gửi privateVariable làm đối số cho hàm, nhưng tôi nghĩ nó đẹp hơn để tránh điều này, và điều tôi thực sự thắc mắc là có lý do chính đáng cho tiêu chuẩn C++ không cho phép chuyên môn hóa rõ ràng như trong ví dụ mã đầu tiên ở trên.


@Arne Mertz: Đây là cách giải quyết mà tôi đã thử nhưng không cho phép sử dụng riêng tư. Và trên hết, tôi tự hỏi có nên làm như thế này hay không. Vì tôi không được phép đưa ra các chuyên môn về các chức năng của thành viên, có lẽ tôi không nên chuyên môn hoá các hàm được đóng gói trong các cấu trúc bên trong lớp.

#include <cstdio> 

namespace MalinTester { 

template <size_t DIMENSIONALITY> 
class SpecializationTest { 
public: 
    SpecializationTest() { 
     privateVariable = 5; 
    }; 
    virtual ~SpecializationTest() {}; 

    void execute() { 
     Loop<DIMENSIONALITY, 0>::execute(); 
    }; 

private: 
    int privateVariable; 

    template <size_t currentDim, size_t DUMMY> 
    struct Loop { 
     static void execute() { 
      printf("This is the general case. Current dim is %d.\n", currentDim); 
      Loop<currentDim-1, 0>::execute(); 
     } 
    }; 

    template <size_t DUMMY> 
    struct Loop<0, DUMMY> { 
     static void execute() { 
      printf("This is the base case. Current dim is 0.\n"); 
     } 
    }; 
}; 
}; 
+0

Có liên quan, tôi nghĩ vậy. http://stackoverflow.com/questions/18294990/why-can-templatet-but-not-template-be-defined-outside-of-a-namespace-block/ – Rapptz

+0

Có vấn đề gì chính xác ở đây? Bạn không thể chỉ đặt chuyên môn vào không gian tên? –

+0

n.m .: Tôi muốn sử dụng các biến cá thể của lớp trong các hàm. Nếu tôi đặt chuyên môn hóa vào không gian tên, bên ngoài lớp, hàm không có quyền truy cập vào nó (trừ khi tôi gửi một thể hiện của lớp thực tế làm đối số cho hàm, nhưng theo ý kiến ​​của tôi, điều đó làm cho mã trở nên xấu hơn.) – Malin

Trả lời

3

cơ sở chuyên môn hóa:

Trong .h:

template <class T> 
class UISelectorSlider : public UISelectorFromRange<T> { 
public: 
    UISelectorSlider(); 
    virtual ~UISelectorSlider(); 
private: 
    float width; 
    float getPositionFromValue(T value); 
}; 

Trong cpp dưới cùng không gian tên:

template <> 
float UISelectorSlider<MVHue>::getPositionFromValue(MVHue value) 
{ 
    return width * (float)value/360.0; 
} 

Nếu bạn muốn chức năng chuyên ngành trong phạm vi lớp học chuyên ngành:

Lớp bên trong thêm (.h) (chức năng tư nhân):

private: 
    template <int I> 
    void foo(); 

Chuyên ngành trong cpp:

template <> 
template <> 
void UISelectorSlider<MVHue>::foo<3>() 
{ 
    // you can access private fields here 
} 

UPDATE:

Nhưng bạn không thể viết một cái gì đó như thế này:

template <class T> 
template <> 
void UISelectorSlider<T>::foo<3>() 
{ 
    // you can access private fields here 
} 

Bạn sẽ nhận được : error: kèm theo các mẫu lớp không chuyên biệt rõ ràng.

Nó không quan trọng là định nghĩa này bên trong lớp hoặc trong không gian tên. Vấn đề là đây không phải là chuyên môn từng phần chính xác - chức năng này không có lớp ngữ cảnh được xác định (thành viên nào bạn muốn gọi). Nói cách khác - khi bạn chuyên thành viên bạn thực sự cố gắng chuyên toàn bộ lớp có chứa, nhưng không phải là thành viên chính nó. Và trình biên dịch không thể làm điều đó bởi vì lớp học chưa được xác định hoàn toàn. Vì vậy, đây là hạn chế bởi thiết kế mẫu. Và nếu nó thực sự làm việc - các mẫu sẽ hoàn toàn tương đương với các macro đơn giản. (Và bạn có thể sẽ giải quyết nhiệm vụ của bạn với một số ma thuật vĩ mô.)

+2

Tôi đánh giá cao rằng mọi người sẵn sàng trả lời, nhưng câu hỏi của tôi là ** nếu có lý do chính đáng cho tiêu chuẩn không cho phép các chuyên ngành của một hàm templatized bên trong một lớp **, không phải cách làm việc xung quanh nó. (Hơn nữa, tôi muốn đóng gói các chức năng trong lớp!) – Malin

+0

Xin lỗi, tôi đã hiểu vấn đề của bạn ngay bây giờ (và chỉnh sửa câu trả lời). –

+0

OK, cảm ơn bạn !! – Malin