0

This prints nothing:

#include <iostream>

template <typename Derived>
struct A
{
    static int test()
    {
        std::cout << "test" << std::endl;
        return 0;
    }

    static inline int a = test();
};

struct B : public A<B>
{
};

int main(int argc, char** argv)
{
    return EXIT_SUCCESS;
}

But this does:

#include <iostream>

template <typename Derived>
struct A
{
};

struct B : public A<B>
{
    static int test()
    {
        std::cout << "test" << std::endl;
        return 0;
    }

    static inline int a = test();
};

int main(int argc, char** argv)
{
    return EXIT_SUCCESS;
}

And also this:

#include <iostream>

struct A
{
    static int test()
    {
        std::cout << "test" << std::endl;
        return 0;
    }

    static inline int a = test();
};

struct B : public A
{

};

int main(int argc, char** argv)
{
    return EXIT_SUCCESS;
}

Not sure why or a workaround. I need the 'Derived' type to register it into a static table.

chila
  • 2,372
  • 1
  • 16
  • 33

3 Answers3

2

The reason why the first snippet doesn't print anything is that the static variable is not instantiated. You have to use that variable in order to instantiate it.

[temp.inst]/2

The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions, default arguments, or noexcept-specifiers of the class member functions, member classes, scoped member enumerations, static data members, member templates, and friends

As a workaround, you can just use that variable:

int main(int argc, char** argv)
{
    (void) B::a;
    return EXIT_SUCCESS;
}
llllllllll
  • 16,169
  • 4
  • 31
  • 54
  • Yeah the implicit question is why the variable isn't initialized. The idea is to avoid any other code so the static function is executed for every derived class automatically. – chila Oct 25 '18 at 15:52
1

Since A is a template class, the static inline function/variable are not actually instantiated from the template unless they are used. Thus, you could do e.g. this:

#include <iostream>

template <typename Derived>
struct A
{
    static int test()
    {
        std::cout << "test" << std::endl;
        return 0;
    }

    static inline int a = test();
};

struct B : public A<B>
{
    static inline int b = a;
};

int main(int argc, char** argv)
{
    return 0;
}

Demo

Max Langhof
  • 23,383
  • 5
  • 39
  • 72
0

The (automatic) solution, as pointed here is to create a constructor that uses the registration variable. Also, the variable will be initialized only if an object is constructed.

#include <iostream>

template <typename Derived>
struct A
{
    A()
    {
        a = 0;
    }

    static int test()
    {
        std::cout << "test" << std::endl;
        return 0;
    }

    static inline int a = test();
};

struct B : public A<B>
{
};

int main(int argc, char** argv)
{
    B b;

    return EXIT_SUCCESS;
}

The 'a = 0' is to avoid a warning of unused variable. Overhead should be minimal.

Demo

chila
  • 2,372
  • 1
  • 16
  • 33