Làm cách nào để buộc một tham số mẫu T
là một lớp con của một lớp cụ thể Baseclass
? Một cái gì đó như thế này:
template <class T : Baseclass> void function(){
T *object = new T();
}
Làm cách nào để buộc một tham số mẫu T
là một lớp con của một lớp cụ thể Baseclass
? Một cái gì đó như thế này:
template <class T : Baseclass> void function(){
T *object = new T();
}
T
nguồn gốc từ Baseclass
. Hiện tại, kiểm tra đó là ẩn và không hiển thị đối với độ phân giải quá tải. Nhưng nếu không có nơi nào một ràng buộc ngầm như vậy được thực hiện, thì dường như không có lý do gì cho một hạn chế giả tạo.
Câu trả lời:
Trong trường hợp này, bạn có thể làm:
template <class T> void function(){
Baseclass *object = new T();
}
Điều này sẽ không biên dịch nếu T không phải là một lớp con của Baseclass (hoặc T là Baseclass).
Với trình biên dịch tuân thủ C ++ 11, bạn có thể làm như sau:
template<class Derived> class MyClass {
MyClass() {
// Compile-time sanity check
static_assert(std::is_base_of<BaseClass, Derived>::value, "Derived not derived from BaseClass");
// Do other construction related stuff...
...
}
}
Tôi đã thử nghiệm điều này bằng cách sử dụng trình biên dịch gcc 4.8.1 bên trong môi trường CYGWIN - vì vậy nó cũng sẽ hoạt động trong môi trường * nix.
template<class TEntity> class BaseBiz { static_assert(std::is_base_of<BaseEntity, TEntity>::value, "TEntity not derived from BaseEntity");
...
Để thực thi mã ít vô ích hơn trong thời gian chạy, bạn có thể xem tại: http://www.stroustrup.com/bs_faq2.html#constraints cung cấp một số lớp thực hiện kiểm tra thời gian biên dịch hiệu quả và tạo ra các thông báo lỗi đẹp hơn.
Đặc biệt:
template<class T, class B> struct Derived_from {
static void constraints(T* p) { B* pb = p; }
Derived_from() { void(*p)(T*) = constraints; }
};
template<class T> void function() {
Derived_from<T,Baseclass>();
}
unused variable 'p'
và unused variable 'pb'
?
(void)pb;
vào sau B* pb = p;
.
Bạn không cần khái niệm, nhưng bạn có thể sử dụng SFINAE:
template <typename T>
boost::enable_if< boost::is_base_of<Base,T>::value >::type function() {
// This function will only be considered by the compiler if
// T actualy derived from Base
}
Lưu ý rằng điều này sẽ khởi tạo hàm chỉ khi điều kiện được đáp ứng, nhưng nó sẽ không cung cấp lỗi hợp lý nếu điều kiện không được đáp ứng.
enable_if
diễn một loại thứ hai tham số mặc định void
. Biểu thức enable_if< true, int >::type
đại diện cho loại int
. Tôi thực sự không thể hiểu câu hỏi đầu tiên của bạn là gì, bạn có thể sử dụng SFINAE cho bất cứ điều gì bạn muốn, nhưng tôi không hiểu bạn định làm gì với điều này trên tất cả các chức năng.
Vì C ++ 11 bạn không cần Boost hoặc static_assert
. C ++ 11 giới thiệu is_base_of
và enable_if
. C ++ 14 giới thiệu kiểu tiện lợi enable_if_t
, nhưng nếu bạn gặp khó khăn với C ++ 11, bạn có thể đơn giản sử dụng enable_if::type
thay thế.
Giải pháp của David Rodríguez có thể được viết lại như sau:
#include <type_traits>
using namespace std;
template <typename T>
enable_if_t<is_base_of<Base, T>::value, void> function() {
// This function will only be considered by the compiler if
// T actualy derived from Base
}
Kể từ C ++ 17, chúng tôi có is_base_of_v
. Giải pháp có thể được viết lại thành:
#include <type_traits>
using namespace std;
template <typename T>
enable_if_t<is_base_of_v<Base, T>, void> function() {
// This function will only be considered by the compiler if
// T actualy derived from Base
}
Bạn cũng có thể chỉ giới hạn toàn bộ mẫu. Bạn có thể sử dụng phương pháp này để xác định toàn bộ các lớp. Lưu ý cách tham số thứ hai của enable_if_t
đã bị loại bỏ (trước đó nó đã được đặt thành void). Giá trị mặc định của nó thực sự là void
, nhưng nó không quan trọng, vì chúng tôi không sử dụng nó.
#include <type_traits>
using namespace std;
template <typename T,
typename = enable_if_t<is_base_of_v<Base, T>>>
void function() {
// This function will only be considered by the compiler if
// T actualy derived from Base
}
Từ tài liệu về tham số mẫu, chúng ta thấy đó typename = enable_if_t...
là tham số mẫu có tên trống. Chúng tôi chỉ đơn giản sử dụng nó để đảm bảo rằng định nghĩa của một kiểu tồn tại. Đặc biệt, enable_if_t
sẽ không được xác định nếu Base
không phải là cơ sở của T
.
Kỹ thuật trên được đưa ra như một ví dụ trong enable_if
.
template <class T : Base>
Bạn có thể sử dụng Boost Concept Check 's BOOST_CONCEPT_REQUIRES
:
#include <boost/concept_check.hpp>
#include <boost/concept/requires.hpp>
template <class T>
BOOST_CONCEPT_REQUIRES(
((boost::Convertible<T, BaseClass>)),
(void)) function()
{
//...
}
Bằng cách gọi các hàm bên trong mẫu của bạn tồn tại trong lớp cơ sở.
Nếu bạn thử và khởi tạo mẫu của mình bằng loại không có quyền truy cập vào chức năng này, bạn sẽ nhận được lỗi thời gian biên dịch.
T
là một BaseClass
vì các thành viên được khai báo trong BaseClass
có thể được lặp lại trong khai báo của T
.