Как назначить значения структуры в функции класса шаблона? - PullRequest
0 голосов
/ 16 октября 2018

У меня есть несколько структур, которые мне нужно добавить к моим векторам и задать им некоторые значения по умолчанию.

  1. Структуры являются внешними, я не могу их изменить.
  2. Хотяприсваивая эти значения, мне для удобства нужно видеть имена членов структуры.
  3. Мне для удобства нужно визуально хранить все значения по умолчанию в одном и том же месте.
  4. В настоящее время компилятор оптимизирует удаление неиспользуемых ветвей в myClass:: addStruct () - это именно то, что я хочу.

В: это можно сделать лучше / проще?

РЕДАКТИРОВАТЬ Я не знаюнет C ++ 17

// внешние структуры

typedef struct A {
    int member1;
    float member2;
    char *member3;
    // ...
} A;

typedef struct B {
    double member5;
    float member3;
    int *member4;
    // ...
} B;

typedef struct C {
    char* member5;
    char* member2;
    float *member3;
    // ...
} C;

...

template <class T>
void myClass::addStruct(std::vector<T> &vp)
{
    void *sp = nullptr;
    if(std::is_same<T, A>::value) {
        A s{};
        s.member1 = 2;
        s.member3 = "whatever";
        sp = &s;
    }
    else if(std::is_same<T, B>::value) {
        B s{};
        s.member4 = nullptr;
        s.member3 = 3.1f;
        sp = &s;
    }
    else if(std::is_same<T, C>::value) {
        C s{};
        s.member2 = "whenever";
        sp = &s;
    }
/*  else if() {
    }
    else if() {
    } ...
*/

    if(sp == nullptr) {
        // print error
        return;
    }

    vp.push_back(*(reinterpret_cast<T*>(sp)));
}

// usage

addStruct<A>(...);
addStruct<A>(...);
addStruct<B>(...);
addStruct<C>(...);

Ответы [ 4 ]

0 голосов
/ 16 октября 2018

Создание фабричных методов:

template <typename T> struct Tag {};

A MakeDefault(Tag<A>) {
    A a{};
    a.member1 = 2;
    a.member3 = "whatever";
    return a;
}

B MakeDefault(Tag<B>) {
    B b{};
    b.member4 = nullptr;
    b.member3 = 3.1f;
    return b;
}

C MakeDefault(Tag<C>) {
    C c{};
    c.member2 = "whenever";
    return c;
}

// ...

template <class T>
void myClass::addStruct(std::vector<T> &vp)
{
    vp.push_back(MakeDefault(tag<T>{}));
}

Я использую диспетчеризацию тегов вместо специализации шаблона, которая здесь кажется более простой.

0 голосов
/ 16 октября 2018
#include <vector>

typedef struct A {
    int member1;
    float member2;
    const char *member3;
    // ...
} A;

typedef struct B {
    double member5;
    float member3;
    int *member4;
    // ...
} B;

typedef struct C {
    char* member5;
    char* member2;
    float *member3;
    // ...
} C;

template <class T>
void addStruct(std::vector<T> &vp)
{
    // print error
}

template <>
void addStruct<A>(std::vector<A> &vp)
{
    A s{};
    s.member1 = 2;
    s.member3 = "whatever";
    vp.push_back(s);
}

template <>
void addStruct<B>(std::vector<B> &vp)
{
    B s{};
    s.member4 = nullptr;
    s.member3 = 3.1f;
    vp.push_back(s);
}

// ...

UPD после Trass3r:

#include <vector>

typedef struct A {
    int member1;
    float member2;
    const char *member3;
    // ...
} A;

typedef struct B {
    double member5;
    float member3;
    int *member4;
    // ...
} B;

typedef struct C {
    char* member5;
    char* member2;
    float *member3;
    // ...
} C;

void addStruct(std::vector<A> &vp)
{
    A s{};
    s.member1 = 2;
    s.member3 = "whatever";
    vp.push_back(s);
}

void addStruct(std::vector<B> &vp)
{
    B s{};
    s.member4 = nullptr;
    s.member3 = 3.1f;
    vp.push_back(s);
}

// ...
0 голосов
/ 16 октября 2018

В: это можно сделать лучше / проще?

Да: это можно сделать без шаблонов, используя функциональный полиморфизм (функции с одинаковым именем и разными аргументами).

typedef struct A {
    int member1;
    float member2;
    char *member3;
    // ...
} A;

typedef struct B {
    double member5;
    float member3;
    int *member4;
    // ...
} B;

...

void myClass::addStruct(std::vector<A>& v)
{
    v.push_back({0});
    v.back().member1 = 2;
    v.back().member3 = "whatever";
}

void myClass::addStruct(std::vector<B>& v)
{
    v.push_back({0});
    // v.back().member4 = nullptr; // this is unnecessary now
    v.back().member3 = 3.1f;
}

...

// usage

std::vector<A> va;
std::vector<B> vb;

myClass c;
c.addStruct(va);
c.addStruct(vb);
0 голосов
/ 16 октября 2018
  1. Код, подобный этому, не должен даже компилироваться, если вы не используете if constexpr (он же "static if")Это только «работает», потому что вы нарушаете систему типов (весь танец void * и reinterpret_cast). Применяются правила наложения имен .
  2. Вы берете адрес объектов, которые уже вышли из области видимости.Это Неопределенное поведение , и во время работы теперь может произойти сбой в любой момент при изменении кода или компилятора или просто версии компилятора.
  3. Если вы действительно хотите пойти с этим кодом, почему бы вам простосоздавать не шаблонные перегрузки для разных типов?Намного проще.
...