2013-02-17 43 views
10

Tôi có một lớp mẫu mà tôi sử dụng để có được kích thước của một biến:Const và mẫu const không chuyên môn hóa

template <class T> 
class Size 
{ 
    unsigned int operator() (T) {return sizeof(T);} 
}; 

này hoạt động tốt nhưng đối với chuỗi Tôi muốn sử dụng strlen thay vì sizeof:

template <> 
class Size<char *> 
{ 
    unsigned int operator() (char *str) {return strlen(str);} 
}; 

Vấn đề là khi tôi tạo một thể hiện kích thước bằng const char *, nó chuyển sang phiên bản không chuyên biệt. Tôi đã tự hỏi nếu có một cách để nắm bắt cả hai phiên bản const và không const của char * trong chuyên môn về mẫu? Cảm ơn.

+1

Tôi không thuyết phục đây là một ý tưởng tốt. Điều gì về trường hợp mà bạn có một '(const) char *' mà không trỏ vào một chuỗi? –

+0

Nó chỉ hoạt động để chỉ chuyên phiên bản 'const'? – Bingo

+0

Không, sau đó khi bạn vượt qua một char không * nó không sử dụng chuyên môn. –

Trả lời

9

Sử dụng kỹ thuật này:

#include <type_traits> 

template< typename T, typename = void > 
class Size 
{ 
    unsigned int operator() (T) {return sizeof(T);} 
}; 

template< typename T > 
class Size< T, typename std::enable_if< 
       std::is_same< T, char* >::value || 
       std::is_same< T, const char* >::value 
       >::type > 
{ 
    unsigned int operator() (T str) { /* your code here */ } 
}; 

EDIT: Ví dụ về làm thế nào để xác định các phương pháp bên ngoài định nghĩa lớp.

EDIT2: Đã thêm trợ giúp để tránh lặp lại điều kiện có thể dài và phức tạp.

EDIT3: Trình trợ giúp được đơn giản hóa.

#include <type_traits> 
#include <iostream> 

template< typename T > 
struct my_condition 
    : std::enable_if< std::is_same< T, char* >::value || 
        std::is_same< T, const char* >::value > 
{}; 

template< typename T, typename = void > 
struct Size 
{ 
    unsigned int operator() (T); 
}; 

template< typename T > 
struct Size< T, typename my_condition<T>::type > 
{ 
    unsigned int operator() (T); 
}; 

template< typename T, typename Dummy > 
unsigned int Size< T, Dummy >::operator() (T) 
{ 
    return 1; 
} 

template< typename T > 
unsigned int Size< T, typename my_condition<T>::type >::operator() (T) 
{ 
    return 2; 
} 

int main() 
{ 
    std::cout << Size<int>()(0) << std::endl; 
    std::cout << Size< char* >()(0) << std::endl; 
    std::cout << Size< const char* >()(0) << std::endl; 
} 

mà in

1 
2 
2 
+1

Cảm ơn, tôi không quen thuộc với cú pháp 'typename = void', làm cách nào để xác định toán tử() nếu tôi muốn viết nội dung hàm bên ngoài lớp và không được gạch chân, trong cả hai trường hợp? –

+1

Nó chỉ là viết tắt của 'typename Dummy = void' trong đó' Dummy' không bao giờ được sử dụng. Tôi sẽ kiểm tra và nâng cao câu trả lời cách xác định 'toán tử()' bên ngoài lớp ... –

+0

Cảm ơn và đối với trường hợp đặc biệt, tôi có cần phải viết toàn bộ điều dài đó trong định nghĩa hàm không? –

4

Một cách là sử dụng một hàm helper để xác định xem các kiểu mẫu là một char * hoặc một char const *. Bạn có thể làm điều này với một cấu trúc đơn giản. Sau đó, bạn có thể sử dụng SFINAE để chọn chuyên môn thích hợp cho cấu trúc Kích thước của mình.

#include <cstring> 
#include <iostream> 

#include <boost/utility/enable_if.hpp> 

template<typename T> 
struct is_cstring { 
    enum { value = false }; 
}; 

template<> 
struct is_cstring<char *> { 
    enum { value = true }; 
}; 

template<> 
struct is_cstring<char const *> { 
    enum { value = true }; 
}; 

template<typename T, typename = void> 
struct Size; 

template<typename T> 
struct Size<T, typename boost::disable_if<is_cstring<T> >::type> { 
    unsigned int operator()(T const &) const { 
    return sizeof(T); 
    } 
}; 

template<typename T> 
struct Size<T, typename boost::enable_if<is_cstring<T> >::type> { 
    unsigned int operator()(T const &str) const { 
    return strlen(str); 
    } 
}; 

int main() { 
    std::string blah = "afafasa"; 
    char *x = "asdfsadsad"; 

    std::cout << Size<int>()(4) << std::endl; 
    std::cout << Size<char const *>()("blahblah") << std::endl; 
    std::cout << Size<char *>()(x) << std::endl; 
} 

Kết quả in là:

4 
8 
10 
-1

Giải pháp đơn giản nhất là thay thế các char * chuyên môn hóa với const char * một. Nó cũng sẽ hoạt động với char *.

template <> 
class Size<const char *> 
{ 
    unsigned int operator() (const char *str) {return strlen(str);} 
}; 
+0

-1 Nếu ai đó sử dụng toán tử 'Kích thước ::()', nó sẽ không sử dụng phiên bản chuyên biệt mà bạn đã hiển thị. –

0

Và bạn cũng nên có khả năng viết, tất nhiên:

template <> 
class Size<const char *> 
{ 
    unsigned int operator() (const char *str) {return strlen(str);} 
}; 

template <> 
class Size<char *> : public Size<const char *> 
{ }; 

... và, bạn nên cần phải:

template <size_t size> 
class Size<char[size]> : public Size<const char *> 
{ }; 

template <size_t size> 
class Size<const char[size]> : public Size<const char *> 
{ }; 
Các vấn đề liên quan