如何在模板类函数中分配结构值?

时间:2018-10-16 10:36:09

标签: c++ visual-c++ factory

我有一堆需要添加到向量中并为其提供默认值的结构。

  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 :(得分:8)

  1. 除非您使用if constexpr(也称为“静态if”),否则此类代码甚至都不会编译。它只会“起作用”,因为您破坏了类型系统(整个void *和reinterpret_cast跳舞)。 Type aliasing rules申请。
  2. 您要获取已经超出范围的对象的地址。那是Undefined Behavior,现在在工作时,在更改代码或编译器或只是编译器版本时可能会随时中断。
  3. 如果您真的想使用该代码,为什么不只为不同类型创建非模板重载呢?更简单。

答案 1 :(得分:3)

#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);
}

// ...

Trass3r之后的UPS:

#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);
}

// ...

答案 2 :(得分:2)

创建工厂方法:

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>{}));
}

我使用标签分配代替模板专门化,这在这里看起来更简单。

答案 3 :(得分:0)

  

问:能否以更好/更简单的方式完成?

是:通过使用函数多态性(具有相同名称和不同参数的函数),可以不使用模板来完成此操作。

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);