2017-12-11 34 views
5

Hãy nói rằng tôi có một lớp mẫu như thế này:Kiểm tra xem một mẫu chuyên môn của một phương pháp tồn tại

template<typename TRequest, typename TResponse = void> 
class handler 
{ 
private: 
    static void validate_core(const TRequest& request); 
    static TResponse process_core(const TRequest& request); 
public: 
    static TResponse process(const TRequest& request) 
    { 
     if (validate_core is implemented) 
     { 
      log("begin validate"); 
      validate_core(request); 
     } 

     return process_core(request); 
    } 
}; 

process_core phải được thực hiện với nhiều loại TRequest/TResponse khác nhau, trong khi validate_core là không bắt buộc, tôi muốn gọi nếu nó được triển khai.

Hiện tại, giải pháp thay thế của tôi đang cung cấp triển khai trống mặc định là validate_core, nếu không chuyên môn thì phương thức trống sẽ được gọi. Tôi muốn biết nếu có một cách tốt hơn.

+1

Có thể trùng lặp của [Sử dụng thành ngữ phát hiện để xác định xem một loại có một constructor với một chữ ký cụ thể] (https://stackoverflow.com/câu hỏi/35669304/sử dụng-phát hiện-thành ngữ-để-xác định-dù-một-loại-có-một-xây dựng-với-như) –

+0

Các dupe liên kết là bao giờ nên hơi khác nhau, như là trường hợp cho các thành ngữ phát hiện nhưng bạn có thể làm việc đó. –

+0

@PasserBy Đối với các phương pháp thông thường tôi thấy một vài giải pháp, tuy nhiên chúng không thích hợp cho các phương thức mẫu. –

Trả lời

-1

Hiện tại, giải pháp thay thế của tôi là cho phép triển khai trống mặc định để validate_core, nếu nó không chuyên biệt thì phương thức trống sẽ được gọi. Tôi muốn biết nếu có một cách tốt hơn.

Dường như với tôi là một cách rất tốt.

Không chắc để hiểu yêu cầu của bạn nhưng tôi giả sử bạn có thể xóa các phiên bản mẫu của validate_core()

và cho phép, bên trong cơ thể của handler, một quặng hơn không mẫu chuyên ngành

static void validate_core (int const &) 
    { /* do something */ } 

    static void validate_core (long const &) 
    { /* do something */ } 

    // ... 

Tiếp theo, bạn có thể thêm, trong phần nội dung của handler, một loại đặc điểm để phát hiện xem có khả năng chuyên môn hóa cho validate_core()

template <typename, typename = void> 
    struct withValidateCore : public std::false_type 
    { }; 

    template <typename T> 
    struct withValidateCore<T, decltype(validate_core(std::declval<T>()))> 
    : public std::true_type 
    { }; 

Nếu bạn có thể sử dụng C++ 17, cách này có thể là thú vị vì nó có sẵn if constexpr(), vì vậy nên có thể một cái gì đó như [xin lỗi: không được thử nghiệm]

static TResponse process (TRequest const & request) 
{ 
    if constexpr (withValidateCore<TRequest>::value) 
    { 
     log("begin validate"); 
     validate_core(request); 
    } 

    return process_core(request); 
} 

Nhưng bạn gắn thẻ C++ 14, do đó, if constexpr() không khả dụng và cách tốt nhất tôi thấy sử dụng withValidateCore là triển khai hai phiên bản khác nhau (SFINAE được bật/tắt) của process(); cái gì đó như

template <typename TRq = TRequest> 
    static std::enable_if_t<(true == withValidateCore<TRq>{}) 
     && (true == std::is_same<TRq, TRequest>{}), TResponse> 
    process (TRequest const & request) 
    { 
    validate_core(request); 

    return process_core(request); 
    } 

    template <typename TRq = TRequest> 
    static std::enable_if_t<(false == withValidateCore<TRq>{}) 
     && (true == std::is_same<TRq, TRequest>{}), TResponse> 
    process (TRequest const & request) 
    { return process_core(request); } 

Nếu không (có thể tốt hơn một chút) một cái gì đó tag-dispatching dựa

private: 
    static TResponse process (TRequest const & request, 
          std::true_type const &) 
    { 
     validate_core(request); 

     return process_core(request); 
    } 

    static TResponse process (TRequest const & request, 
          std::false_type const &) 
    { return process_core(request); } 

public: 
    static TResponse process (TRequest const & request) 
    { return process(request, withValidateCore<TRequest>{}); } 

IMHO nó tốt hơn (trong C++ 14) là giải pháp dựa trên một phiên bản generic trống validate_core().

Dù sao, sau đây là một ví dụ làm việc toàn

#include <iostream> 
#include <type_traits> 

template <typename TRequest, typename TResponse = void> 
class handler 
{ 
    private: 
     template <typename TRq = TRequest> 
     static void validate_core (TRequest const &) = delete; 

     static void validate_core (int const &) 
     { std::cout << "- validate_core() int case" << std::endl; } 

     static void validate_core (long const &) 
     { std::cout << "- validate_core() long case" << std::endl; } 

     static TResponse process_core (const TRequest &) 
     { return TResponse(); } 

     template <typename, typename = void> 
     struct withValidateCore : public std::false_type 
     { }; 

     template <typename T> 
     struct withValidateCore<T, decltype(validate_core(std::declval<T>()))> 
     : public std::true_type 
     { }; 

    public: 
     template <typename TRq = TRequest> 
     static std::enable_if_t<(true == withValidateCore<TRq>{}) 
      && (true == std::is_same<TRq, TRequest>{}), TResponse> 
     process (TRequest const & request) 
     { 
     validate_core(request); 

     return process_core(request); 
     } 

     template <typename TRq = TRequest> 
     static std::enable_if_t<(false == withValidateCore<TRq>{}) 
      && (true == std::is_same<TRq, TRequest>{}), TResponse> 
     process (TRequest const & request) 
     { return process_core(request); } 
}; 

int main() 
{ 
    handler<int>::process(0);  // print - validate_core() int case 
    handler<int, long>::process(0); // print - validate_core() int case 
    handler<long>::process(0);  // print - validate_core() long case 
    handler<char>::process(0);  // no print 
} 
0

Nó không phải là có thể kiểm tra tại thời gian biên dịch nếu một mẫu chuyên môn được thực hiện. Tốt nhất bạn có thể tạo ra một lỗi thời gian liên kết bằng cách khai báo và khởi tạo mẫu bên ngoài.

Tôi hiểu rằng bạn muốn rằng process triển khai mẫu thiết kế phương pháp mẫu mẫu. Nếu trường hợp này xảy ra, bạn có thể thấy việc sử dụng CRTP dưới đây thú vị.(Nota bene: Tôi đã sửa đổi chức năng chữ ký để làm cho mã này compilable)

template<class Derived, typename TRequest, typename TResponse> 
class handler_base 
{ 
private: 
//caution trickery 
static constexpr bool validate_core=false; 

public: 
static TResponse* process(const TRequest& request) 
    { 
    if constexpr (Derived::validate_core) 
    { 
     //log("begin validate"); 
     Derived::validate_core(request); 
    } 

    return Derived::process_core(request); 
    } 
}; 

template<typename TRequest, typename TResponse=void> 
class handler; 

class Req1; 
class Req2; 
class Resp1; 
class Resp2; 

template<> 
class handler<Req1,Resp1> 
    : handler_base<handler<Req1,Resp1>,Req1,Resp1> 
    { 
    static void validate_core(const Req1& request); 
    static Resp1* process_core(const Req1& request); 
    friend handler_base; 
    }; 

template<> 
class handler<Req2,Resp2> 
    : handler_base<handler<Req2,Resp2>,Req2,Resp2> 
    { 
    friend handler_base; 
    static Resp2* process_core(const Req2& request); 
    }; 
//just to force compilation 
template Resp2* handler_base<handler<Req2,Resp2>,Req2,Resp2>::process(const Req2&); 
template Resp1* handler_base<handler<Req1,Resp1>,Req1,Resp1>::process(const Req1&); 
Các vấn đề liên quan