2012-09-27 48 views
9

tôi thấy ví dụ sau của enable_if cho C++ 11:C++ 11 lỗi enable_if

struct is_64_bit 
{ 
    static const bool value = sizeof(void*) == 8; 
}; 

enable_if<is_64_bit::value, void>::type 
my_memcpy(void* target, const void* source, size_t n) 
{ 
    cout << "64 bit memcpy" << endl; 
} 

enable_if<!is_64_bit::value, void>::type 
my_memcpy(void* target, const void* source, size_t n) 
{ 
    cout << "32 bit memcpy" << endl; 
} 

Theo tôi được biết, tùy thuộc vào kiến ​​trúc hệ thống, các "my_memcpy" chức năng sẽ có sẵn trong hai cho 32 hoặc các phiên bản 64 bit. Nhưng tôi nhận được lỗi sau khi biên soạn:

error: ‘type’ in ‘struct std::enable_if<false, void>’ does not name a type 

Tôi hơi bối rối vì tôi nghĩ chỉ có phiên bản 32 có sẵn (tôi đang sử dụng Linux Fedora 32 bit).

Có thể đã xảy ra sự cố với ví dụ này? hoặc Tôi thiếu cái gì?

Cảm ơn.

Trả lời

9

Mẫu template< bool B, class T = void > struct enable_if chuyên dùng để chỉ có typedef type khi điều kiện B là true.

Trình biên dịch của bạn là chính xác. Không có typedef cho type trong struct std::enable_if<false, void>. Chỉ có một typedef trong struct std::enable_if<true, void>.

Để biết thêm thông tin, hãy xem here.

Vì vậy, để khắc phục sự cố của bạn, bạn cần đảm bảo rằng enable_if có B đánh giá là false không bao giờ được biên dịch. Bạn có thể đạt được điều này với sự trợ giúp của SFINAE bằng cách tạo my_memcpy mẫu chức năng. Trình biên dịch sau đó sẽ không báo cáo lỗi khi không biên dịch mẫu chức năng trong đó B đánh giá thành false và sẽ biên dịch thành công và sử dụng hàm mà B đánh giá là true.

#include <iostream> 
#include <type_traits> 

using namespace std; 


struct is_64_bit 
{ 
    static const bool value = sizeof(void*) == 8; 
}; 

template<typename T> 
typename enable_if<is_64_bit::value, T>::type 
my_memcpy(T* target, const T* source, size_t n) 
{ 
    cout << "64 bit memcpy" << endl; 
} 

template<typename T> 
typename enable_if<!is_64_bit::value, T>::type 
my_memcpy(T* target, const T* source, size_t n) 
{ 
    cout << "32 bit memcpy" << endl; 
} 
+0

Cảm ơn cyon. Nó được giải quyết ngay bây giờ. Ngoài ra tôi có một sự hiểu biết tốt hơn về chủ đề này. :) – user1274605

10

std::enable_if công trình thông qua các nguyên tắc substitution failure is not an error (SFINAE), trong đó nêu rằng khi một số loại lỗi xảy ra trong instantiating một hàm mẫu, chương trình tiếp tục biên soạn với hàm mẫu không tham gia vào giải quyết tình trạng quá tải.

Để SFINAE khởi động, (a) nó phải được sử dụng trên mẫu hàm (hoặc phương pháp) và (b) nó phải phụ thuộc vào thông số mẫu. Chương trình của bạn không thành công trên cả hai lần đếm.

Để thực hiện enable_if phụ thuộc vào một số mẫu, điều đơn giản nhất là để thêm một tham số mặc định:

template<typename T = void> typename enable_if<is_64_bit::value, T>::type 
my_memcpy(void* target, const void* source, size_t n) 

Tuy nhiên, đây không phải là trong việc sử dụng hợp lý chung của enable_if; vì nó phụ thuộc vào việc chặn các lỗi biên dịch nó có xu hướng đắt tiền. Trong trường hợp của bạn, một chuyên môn về mẫu sẽ là một ý tưởng tốt hơn nhiều:

#include <iostream> 

template<int = sizeof(void *)> void my_memcpy(void* target, const void* source, size_t n); 

template<> void my_memcpy<8>(void* target, const void* source, size_t n) { 
    std::cout << "64 bit memcpy" << std::endl; 
} 

template<> void my_memcpy<4>(void* target, const void* source, size_t n) { 
    std::cout << "32 bit memcpy" << std::endl; 
} 
+0

+1 cho "Để SFINAE khởi động, (a) nó phải được sử dụng trên mẫu hàm (hoặc phương thức) và (b) nó phải phụ thuộc vào tham số mẫu." Bây giờ tôi thực sự nhận được nó. – Claudiu

3

SFINAE là dành cho mẫu. Những gì bạn cần là sử dụng các mẫu, như các câu trả lời khác được đề cập, hoặc chỉ có một thời gian biên dịch, IMO là giải pháp thích hợp hơn (thay vì giới thiệu một mẫu không cần thiết):

struct is_64_bit : 
    std::integral_constant<bool, sizeof(void*) == 8> 
{}; 

namespace detail 
{ 
    void my_memcpy(void* target, const void* source, std::size_t n, std::true_type) 
    { 
     std::cout << "64 bit memcpy" << std::endl; 
    } 


    void my_memcpy(void* target, const void* source, std::size_t n, std::false_type) 
    { 
     std::cout << "32 bit memcpy" << std::endl; 
    } 
} 

void my_memcpy(void* target, const void* source, std::size_t n) 
{ 
    my_memcpy(target, source, n, is_64_bit()); 
}