3
votes

I would like to determine the sizeof a particular member variable for a struct type that I am passing as a template argument to a function. However, I get an error from the compiler saying that the sizeof operand is illegal (I am using VS2010 with Windows 7).

Consider the following program:

#include <vector>
#include <fstream>

struct MyFloat {
    float val;
    MyFloat(){val=rand()/(RAND_MAX+1.f);};
};
struct MyDouble {
    double val;
    MyDouble(){val=rand()/(RAND_MAX+1.);};
};

template<class T>
void serializeArrayToFile(const std::string &filename, const std::vector<T> &items) {
    const size_t nbytes = sizeof(T::val); // <--- Error C2070
    std::ofstream os(filename.c_str(),std::ios::out+std::ios::binary);
    for(size_t i=0; i<items.size(); ++i)
        os.write((char*)(&items[i].val),nbytes);
    os.close();
};

void main() {
    const int N = 15;
    std::vector<MyFloat> arr_float(N); // Filled randomly by default constructor
    std::vector<MyDouble> arr_double(N); // Filled randomly by default constructor
    serializeArrayToFile<MyFloat>("myfloat_array.dat",arr_float);
    serializeArrayToFile<MyDouble>("mydouble_array.dat",arr_double);
}

This generates the following error: error C2070: '' : illegal sizeof operand.

Can someone explain why sizeof(T::val) is illegal and how I should determine the sizeof T::val, considering that the input vector could be empty ?

1
The expression under sizeof is not evaluated, so you can safely use items[0].val.n. 1.8e9-where's-my-share m.
@n.m Interesting, I did not know that. Any idea why this particular sizeof expression fails?BConic

1 Answers

5
votes

Applying sizeof to a non-static data member named without an object is a C++11 feature; it was introduced into the language in paper n2253. A conforming C++03 compiler will not allow that usage; if possible you should see if you can use a conforming C++11 compiler.

[Note that contrary to that paper, sizeof(S::m + 42) is actually allowed in the final C++11 standard; I'm not sure when that was changed.]

The general workaround is to dereference a null pointer (valid in a non-evaluated context):

sizeof(((T*) 0)->val)

However, you have an object of type T available, so can write:

sizeof(items.front().val)

This is valid even if the vector is empty, because sizeof is a non-evaluated context so front() will not actually be called.