Мне предоставлен набор классов, которые я не могу изменить. (Для любопытных: они автоматически генерируются из моделей Simulink). К сожалению, эти классы делают слишком много вещей общедоступными. Итак, я решил написать класс интерфейса для всех этих классов, который инкапсулирует их и делает их использование немного безопаснее. Однако у меня возникли проблемы с написанием одного класса интерфейса (шаблона), который работал бы для всех возможных классов.
Большинство классов определяют структуру под названием MyStruct, которую я необходимо использовать внутри класса интерфейса. Однако я не хочу использовать это имя по разным причинам и вместо этого хотел бы использовать псевдоним внутри класса интерфейса. В итоге у меня получился следующий код:
Код: Выделить всё
// Classes to interface with
class MyClass1
{
public:
struct MyStruct
{
double f1;
double f2;
} _myVar {};
};
class MyClass2
{
public:
struct MyStruct
{
double g1;
double g2;
double g3;
} _myVar {};
};
class MyClass3
{};
// Interface class
template
class Interface
{
public:
using MyAlias = typename T::MyStruct;
void setVar(const MyAlias& newVar) {_object._myVar = newVar;};
void doSomething()
{
MyAlias inputs {};
}
private:
T _object {};
};
// Main function
int main()
{
Interface i1; // compiles fine
Interface i2; // compiles fine
Interface i3; // compile error: no type named ‘MyStruct’ in ‘class MyClass3’
return 0;
}
Я пытался определить псевдоним и метод только в том случае, если тип определен, и наткнулся на концепцию SFINAE. К сожалению, я не могу использовать в своем коде ничего из стандартной библиотеки. Поэтому такие вещи, как std::enable_if или std::void_t, не обсуждаются. Искусственный интеллект предложил следующие решения для псевдонима и метода:
Код: Выделить всё
template
struct check_mystruct {using type = void; };
template
struct check_mystruct { using type = typename U::MyStruct; };
using MyAlias = typename check_mystruct::type;
Код: Выделить всё
template
void setVar(const U& newVar) {_object._myVar = newVar;};
void setVar(...) { /* do nothing */ };
Однако, если я объединил их в исходную программу следующим образом: :
Код: Выделить всё
// Classes to interface with
class MyClass1
{
public:
struct MyStruct
{
double f1;
double f2;
} _myVar {};
};
class MyClass2
{
public:
struct MyStruct
{
double g1;
double g2;
double g3;
} _myVar {};
};
class MyClass3
{};
// Interface class
template
class Interface
{
public:
template
struct check_mystruct {using type = void; };
template
struct check_mystruct { using type = typename U::MyStruct; };
using MyAlias = typename check_mystruct::type;
template
void setVar(const U& newVar) {_object._myVar = newVar;};
void setVar(...) { /* do nothing */ };
void doSomething()
{
MyAlias inputs {};
}
private:
T _object {};
};
// Main function
int main()
{
Interface i1; // compiles fine
Interface i2; // compiles fine
Interface i3; // compiles fine
i1.doSomething(); // compile error: In instantiation of ‘void Interface::doSomething() [with T = MyClass1]’: variable or field ‘inputs’ declared void
i2.doSomething();
i3.doSomething();
return 0;
}
Код: Выделить всё
main.cpp: In instantiation of ‘void Interface::doSomething() [with T = MyClass1]’:
main.cpp:58:19: required from here
main.cpp:44:17: error: variable or field ‘inputs’ declared void
44 | MyAlias inputs {};
| ^~~~~~
Источник: https://stackoverflow.com/questions/781 ... in-a-class
Мобильная версия