Template arguments to operator (over loading)

Viewed 41

I have a struct that is "templated" like this:

template<int _WM_BITS>
struct STD_LOGIC_VECTOR_32 {
  const int s_Bits = _WM_BITS;
  int other data
};

I have two overloaded function templates for the * operator:

int operator*(STD_LOGIC_VECTOR_32<0> a, STD_LOGIC_VECTOR_32<1> b) {
   // ... want to throw a compile time error with static_assert
}
int operator*(STD_LOGIC_VECTOR_32<0> a, STD_LOGIC_VECTOR_32<0> b) {
   // ... blah no error
}

At the moment, the compilation always fails (and I understand why). However, the erroring function is never called and therefore should never be in the program text once compilation has completed, so the static_assert is too early in the compiler process to detect this. I understand and accept this too.

The question is: How can I parameterize the * operator overload function to include all integer template values of STD_LOGIC_VECTOR_32 and then catch the invocations where the template parameters are not the same? This information is available to the compiler, as each concrete instance of STD_LOGIC_VECTOR_32 must be instantiated in the code with:

struct STD_LOGIC_VECTOR_32<24> a;

Therefore, the compiler knows which * operator function to use and the const element in the struct is initialized at compile time to a specific, immutable value.

I think the order of compilation processing is going to get the better of me, but I thought I would ask the question; after all C++ is supposed to be a multi-pass compilation process.

1 Answers

Make your * operator a function template that takes the size(s) as its template parameters:

template<int _WM_BITS>
struct STD_LOGIC_VECTOR_32 {
    const int s_Bits = _WM_BITS;
    int other_data;
};

template<int N, int M>
int operator*(STD_LOGIC_VECTOR_32<N> a, STD_LOGIC_VECTOR_32<M> b)
{
    static_assert(N == M, "Sizes don't match");
    // ... do stuff ...
    return 0;
}

int main()
{
    STD_LOGIC_VECTOR_32<0> a, b;
    STD_LOGIC_VECTOR_32<1> c;
    auto d = a * b; // OK
    auto e = a * c; // error : static_assert failed due to requirement '0 == 1' "Sizes don't match"
    return 0;
}

Alternatively, as the two sizes have to be the same, you can simply have only one template parameter:

template<int N>
int operator*(STD_LOGIC_VECTOR_32<N> a, STD_LOGIC_VECTOR_32<N> b)
{
    // ... do stuff ...
    return 0;
}

But then the error is different: the auto e = a * c; statement from the above main will generate:

error : invalid operands to binary expression ('STD_LOGIC_VECTOR_32<0>' and 'STD_LOGIC_VECTOR_32<1>')

So, if you want to force the use of the static_assert, then stick with the two-int template.

Related