简体   繁体   中英

Static variable inside a template base class

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.

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

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 eg 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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM