2017-02-23 41 views
6

Tôi hiện đang suy nghĩ về cách tốt nhất hạn chế loại chung của mẫu thành std::sting cũng như chuỗi ký tự. Do đó tôi so sánh loại suy luận với loại mong muốn sử dụng std::is_same. Trong trường hợp của std::string, tính năng này hoạt động ngay lập tức. Đối với chuỗi ký tự, nghĩa là mảng char const, nó chỉ hoạt động nếu tôi sử dụng std::decay trên loại và sau đó so sánh kết quả với loại char const *. Nếu tôi trực tiếp so sánh loại suy luận với điều tôi nghĩ, is_same trả về false, như được minh họa bằng mã ví dụ sau.Khấu trừ đối số mẫu từ chuỗi Literal

template <class TYPE> 
void function(TYPE&& parameter) 
{ 
    //this doesn't work as expected 
    std::cout << typeid(TYPE).name() << " : " << typeid(char const [5]).name() << std::endl; 
    std::cout << std::is_same<char const [5], TYPE>::value << std::endl; 
    //this works as expected 
    std::cout << typeid(std::decay_t<TYPE>).name() << " : " << typeid(char const *).name() << std::endl; 
    std::cout << std::is_same<char const *, std::decay_t<TYPE>>::value << std::endl; 
} 

int main(int argc, char** argv) 
{ 
    function("name"); 
    return 0; 
} 

Sản lượng được tạo ra như sau:

char const [5] : char const [5] 
0 
char const * __ptr64 : char const * __ptr64 
1 

Bây giờ, những gì tôi đang tự hỏi là tại sao is_same false trả trong trường hợp đầu tiên mặc dù các loại dường như giống hệt nhau.

Giải thích duy nhất mà tôi có thể đưa ra là trong hàm std::is_same phép chuyển đổi tương tự như std::decay được áp dụng cho loại (ví dụ: cuộc gọi hàm). Nhưng sau đó một lần nữa chuyển đổi này cũng sẽ xảy ra với loại khác, cho kết quả tương tự và do đó dẫn đến sự bình đẳng.

+0

Đợi đến khi C++ 17 và viết mẫu của bạn để sử dụng 'std :: string_view'. –

+1

Thử xóa tham chiếu khỏi 'TYPE'. String literals là các giá trị. –

+0

Cảm ơn bạn, bạn đã đúng. Tôi không biết điều đó. Thay đổi dòng thành 'std :: is_same > :: giá trị' dẫn đến sự bình đẳng. Tại sao các chuỗi ký tự được coi là giá trị? Nếu nó là một chữ int thay vì nó sẽ được coi là một rvalue, phải không? Và chúng ta có thể làm cho câu trả lời này được chấp nhận không? – user1488118

Trả lời

6

literals chuỗi không thông qua giá trị như char const [N], nhưng bởi tham khảo như char const (&)[N].

này hoạt động một cách chính xác cho tôi:

std::cout << std::is_same<char const (&)[5], TYPE>::value << std::endl; 

Note here rằng

1) Đề cập đến một đối tượng std::type_info đại diện cho kiểu loại. Nếu loại là loại tham chiếu, kết quả đề cập đến đối tượng std::type_info thể hiện loại được tham chiếu.

Bạn có thể dễ dàng xác minh rằng is_same không loại bỏ tài liệu tham khảo-Ness trong cùng một cách như type_info, ví dụ bằng cách kiểm tra rằng

std::is_same<int&, int>::value == false 

Điều này giải thích tại sao tên typeid là như nhau, nhưng bạn is_same kiểm tra vẫn không thành công.

2

Sử dụng chức năng tùy chỉnh gcc:

template < class T > 
constexpr std::string type_name() 
{ 
    std::string p = __PRETTY_FUNCTION__; 
    return p.substr(43 + 10, p.length() - 100 - 1 - 10); 
} 

Và thêm nó vào mã của bạn:

std::cout << type_name<TYPE>() << " : " << type_name<char const [5]>() << std::endl; 

Kết quả là:

A5_c : A5_c 
0 
const char (&)[5] : const char [5] 

Vì vậy, bạn cần phải sử dụng std::remove_reference trên TYPE.

+0

Tôi nghĩ rằng bạn có quyền liên quan đến các hiệu ứng. Tuy nhiên, nguyên nhân cho điều này đã được đề cập bởi Kerrek SB trong các ý kiến: chuỗi chữ rõ ràng là lvalues, không rvalues. Do đó loại được suy ra dưới dạng 'T &' thay vì 'T' khi được truyền qua tham số tham chiếu chuyển tiếp. – user1488118

+0

@ user1488118 Khi bạn sử dụng cùng một chuỗi chữ trong mã của bạn, ví dụ như chuỗi "' "ở những nơi khác nhau, nó thực sự là cùng một chuỗi. Nó không phải là tạm thời mới mỗi lần, nhưng nó vẫn còn trong bộ nhớ miễn là chương trình đang chạy, vì vậy khi bạn đề cập đến nó, bạn thực sự đề cập đến nó bằng tham chiếu l-value. – xinaiz

0

Nó có thể là một sai lầm của trình biên dịch. Trình biên dịch tạo ra các loại đối tượng được đưa ra bởi typeid tại compiletime. Trình biên dịch sẽ không biên dịch các kiểu mảng cho mỗi độ dài (0 đến 2 ** n), do đó, nó biên dịch chúng khi cần thiết và nó có thể "quên" về bản sao. Hãy thử sử dụng một mẫu đặc biệt, nơi bạn tách độ dài khỏi loại có chứa. Đây không phải là loại nhưng bạn có thể kiểm tra xem nó có bằng loại khác hay không.

template<class T, size_t size> 
struct array_t{}; 

    template <class T, size_t size> 
void function(T[size] parameter) { 
    std::cout << typeid(array_t<T, size>).name() << " : " << typeid(array_t<char, 5>).name() << std::endl; 
    std::cout << std::is_same<array_t<T, size>, array_t<char, 5>>::value << std::endl; 
}; 
Các vấn đề liên quan