我有一个奇怪的用例。这是它的非常简化的版本。
假设我有一个Base
类和一个DerivedOne
和DerivedTwo
类,它们是从Base
类派生的。
然后有一个枚举:
enum DerClasses {Derived1, Derived2};
和一个函数,该函数将使用一个枚举并根据值返回派生类的实例。
类似的东西:
inline Base* create_instance(DerClasses enum_class){
switch(enum_class) {
case Derived1:
return new Derived1();
case Derived2:
return new Derived2();
}
}
显然这是可行的,但此后才强制转换为派生类。
Derived1 *derived_pointer = dynamic_cast<Derived1*>(pointer);
我不希望用户自己进行这些动态转换,甚至不了解类。
是否可以通过某种方式隐藏这些强制类型转换,并使API具有自动类型推断功能,例如
auto ptr = create_instance(DerClasses::Derived1);
ptr->derived1_class_only_variable = 123;
答案 0 :(得分:3)
template<DerClasses enum_class>
auto create_instance(){
if constexpr (enum_class == DerClasses::Derived1) {
return std::make_unique<Derived1>();
else if constexpr (enum_class == DerClasses::Derived2) {
return std::make_unique<Derived2>();
}
如果在编译时不知道DerClasses
的值,则此方法将无效,也将无法正常工作。您可以获得的最接近的是延续传递样式:
template<class F>
decltype(auto) create_instance(DerClasses enum_class, F&& f){
switch(enum_class) {
case DerClasses::Derived1:
return f(std::make_unique<Derived1>());
case DerClasses::Derived2:
return f(std::make_unique<Derived2>());
}
}
其用法类似于:
create_instance(DerClasses::Derived1, [&](auto&& ptr) {
if constexpr( std::is_same< std::decay_t<decltype(*ptr)>, Derived1 >{} )
ptr->derived1_class_only_variable = 123;
});
但是那也很糟糕,因为lambda是用两种派生类型调用的;只运行一次。
使用覆盖可能会起作用,但是您又一次发疯了。
答案 1 :(得分:2)
您可以使用一些元编程来做到这一点。如果您使用的是C ++ 11/14,则可以执行以下操作:
private void populatelistView() {
final Cursor res = userDb.getAllRows();
final String[] fromFeildnames = new String[]{ DatabaseUser.KEY_1, DatabaseUser.KEY_2};
final int[] toViewIds = new int[]{R.id.textViewNum, R.id.textViewItem};
final SimpleCursorAdapter myCursorAdaptor;
myCursorAdaptor = new SimpleCursorAdapter(getBaseContext(), R.layout.item_layout, res, fromFeildnames, toViewIds, 0){
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = getLayoutInflater();
View rowView = inflater.inflate(R.layout.item_layout, null, true);
delete= (Button)rowView.findViewById(R.id.deleteItem);
delete.setTag(position);
Cursor cursor = (Cursor) mylist.getItemAtPosition(position);
String listName = cursor.getString(1);
String displayName = db.getName(listName);
TextView textView = (TextView) rowView.findViewById(R.id.textViewItem);
textView.setText(displayName);
View.OnClickListener() {
@Override
public void onClick(View v) {
View parentRow = (View) v.getParent();
ListView listView = (ListView) parentRow.getParent();
final int position = listView.getPositionForView(parentRow);
Cursor cursor = (Cursor) mylist.getItemAtPosition(position);
Toast.makeText(getApplicationContext(), "Button " + position, Toast.LENGTH_SHORT).show();
}
});
return rowView;
}
};
mylist.setAdapter(myCursorAdaptor);
}
然后您的代码就变成了您所说的:
enum class ClassType {
FirstType,
SecondType,
ThirdType
};
namespace internal {
template <ClassType Type>
struct _build_type {};
template <>
struct _build_type<ClassType::FirstType> {
constexpr auto operator()() {
return std::make_unique<MyFirstType>();
}
};
template <>
struct _build_type<ClassType::SecondType> {
constexpr auto operator()() {
return std::make_unique<MySecondType>();
}
};
template <>
struct _build_type<ClassType::ThirdType> {
constexpr auto operator()() {
return std::make_unique<MyThirdType>();
}
};
}
template <WindowType Type>
constexpr auto create_instance() {
return internal::_build_type<Type>{}();
}
在现代C ++ 17中,您可以使用简单的auto ptr = create_instance<ClassType::FirstType>();
ptr->derived1_class_only_variable = 123;
条件来简化代码。