2

Lately I practiced the use of template in c++, and I am confused about one of the template parameters during the process.

For instance, in the following code, the input A of template<typename A> served as a 'type' to construct function and variables.

template <typename A>
A add_simple(A a, A b)
{
    return a + b;
}

However, in the following example, a unit conversion operation, it seems the input M1 and M2 serve as objects. In main(), I've shown how the struct is expected to be called.

// create a template struct Measure with value and unit. e.g. Measure<int, Unit>::value
template<int v, Unit u> struct Measure{
    static const int value=v;
    static const Unit unit=u;
};

// Conversion struct. expected input two 'Measure' objects. 
template <typename M1, typename M2> 
struct Measure_add {
public:
    // other implementation

    static constexpr int value=M1::value+M2::value;
};

int main(int, char**) {

    std::cout << Measure_add< Measure<10,Unit::m>,
        Measure<20,Unit::m> >::value << std::endl;

}

So my confusion about template is:

  1. Is <template> designed to be such flexible that it dynamically distinguish the input so both a 'type' input and 'object' input works. Or the difference met here because the expected inputs are constructed template input Measure? As a result, M1 and M2 are still 'type', Measure. And in this case, why M1::value is available if M1 is a type instead of an object?

  2. Why is it available to get access to M1::value or M2::value in template struct Measure_add though the inputs are unknown to such struct. In other words, if I input other parameters which don't contain attribute value, would it cause problem?

Daraan
  • 1,797
  • 13
  • 24
Chrsi
  • 93
  • 5
  • 2
    If `value` is a __static__ data member, you don't need an object, only a type. That's what `static` is for. – Evg Jan 08 '23 at 21:24
  • @Evg Thanks. And why can the struct I showed here accept unkown attribute of M1, M1::value? What if the inputs M1 and M2 are not `Measure` type or they don't have attribute named `value`? – Chrsi Jan 08 '23 at 21:30
  • Any types with `value` static data members will work in your code example. If either doesn't have a `value` static data member, you'll get a compilation error. – Evg Jan 08 '23 at 21:35
  • @Chrsi you could just try it, right? Pass int as m1 and see what happens. Also: does the code compile as you posted it? I'm surprised that you initialize a constexpr variable from const variables, I would expect that not to work. – Wutz Jan 08 '23 at 21:36
  • @Wutz Yes, I've tried and they are good to be compiled and run. I just don't know why it works though :[. – Chrsi Jan 08 '23 at 21:38
  • 1
    @Wutz It's possible because `const` variable initialized with a literal value is treated as a constant expression. See here: https://stackoverflow.com/questions/45593044/the-value-of-a-const-variable-is-or-is-not-usable-in-a-constant-expression-depe – Evg Jan 08 '23 at 21:41
  • Unrelated: it should be `static constexpr int` or `inline static const int` (if for some reason it can't be `constexpr`) to avoid [potential linkage problems](https://godbolt.org/z/q9Tzd65je). – Evg Jan 08 '23 at 21:51

1 Answers1

1

In your code both M1 and M2 are type template parameters. The reason why you can say M::value is that value is a static data member in a type that is substituted for M. That's the point of a static data member: you don't need an object to access its value. This is not related to templates:

struct M {
    static constexpr int value = 0;
};

int foo() {
    return M::value;   // OK
}

M1 and M2 are not constrained to being specializations of Measure template: they can be any types that have a static value data member. For other types that don't satisfy this condition you'll simply get a compilation error.

std::cout <<
    Measure_add<
        std::integral_constant<int, 10>,
        std::integral_constant<int, 20>
    >::value;  // compiles, prints 30

and

std::cout << 
    Measure_add<
        Measure<10, Unit::m>,
        std::integral_constant<int, 20>
    >::value;  // compiles, prints 30, but makes no sense
Evg
  • 25,259
  • 5
  • 41
  • 83