Шаблонная функция и static переменная

Подскажите пожалуйста, а как нужно правильно реализовать static переменную в шаблонной функции ?

Ну то есть вот так, как с обычной функцией нельзя: компилятор ругается на переопределение переменной my_int:

static int my_int;

template <typename char_wchar_type>

int my_func_shablon_1(char_wchar_type* my_char_p)  
{
  //.....

    return 0;
}

.

static int my_int;

template <typename string_wstring_type>

int my_func_shablon_2(string_wstring_type my_string) 
{
  //.....
    return 0;
}

.

#include "my_func_shablon_1.h"
#include "my_func_shablon_2.h"

int main()
{

}

А как тогда можно сделать static переменную для конкретного .h - файла ? Или это невозможно ?


Ответы (2 шт):

Автор решения: DmitryK

Неважно в каком файле вы объявляете переменную. Препроцессор просто вставляет текст из файлов .h в файл с функцией main(). И получается двойное объявление переменной.
Можно использовать директивы препроцессора

#ifndef MY_INT
#define MY_INT 
static int my_int=0;
#endif

Но проще обе функции описать в одном .h-файле

→ Ссылка
Автор решения: Stanislav Volodarskiy

Поместите статическую переменную в шаблон. Компилятор и компоновщик гарантируют что дублирующиеся определения этой переменной будут объединены вместе.

t.hpp:

#ifndef T_HPP_
#define T_HPP_

template <typename T_> struct T {
    static T_ v;
};
template <typename T_> T_ T<T_>::v;

#endif // #ifndef T_HPP_

Два правила:

  1. Во всех единицах трансляции T<int>::v ссылается на одну и ту же переменную.

  2. T<int>::v и T<double>::v ссылаются на две разные переменные.

Демонстрация:

m1.hpp:

#ifndef M1_HPP_
#define M1_HPP_

namespace m1 {
    int    get_int   ();
    double get_double();
    void   add_int   (int    v);
    void   add_double(double v);
} // namespace m1

#endif // #ifndef M1_HPP_

m2.hpp:

#ifndef M2_HPP_
#define M2_HPP_

namespace m2 {
    int    get_int   ();
    double get_double();
    void   add_int   (int    v);
    void   add_double(double v);
} // namespace m2

#endif // #ifndef M2_HPP_

m1.cpp:

#include <m1.hpp>

#include <t.hpp>

namespace m1 {
    int    get_int   () { return T<int   >::v; }
    double get_double() { return T<double>::v; }
    void   add_int   (int    v) { T<int   >::v += v; }
    void   add_double(double v) { T<double>::v += v; }
} // namespace m1

m2.cpp:

#include <m2.hpp>

#include <t.hpp>

namespace m2 {
    int    get_int   () { return T<int   >::v; }
    double get_double() { return T<double>::v; }
    void   add_int   (int    v) { T<int   >::v += v; }
    void   add_double(double v) { T<double>::v += v; }
} // namespace m2

main.cpp:

#include <iostream>

#include <m1.hpp>
#include <m2.hpp>

int main() {
    std::cout << m2::get_int() << ' ' << m2::get_double() << '\n';
    m1::add_int(2);
    m1::add_double(3);
    std::cout << m2::get_int() << ' ' << m2::get_double() << '\n';
}
$ g++ -std=c++17 -pedantic -Wall -Wextra -Werror -I. main.cpp m1.cpp m2.cpp
$ ./a.out 
0 0
2 3

Модули m1 и m2 делят общее состояние, целиком описанное в заголовке t.hpp.

→ Ссылка