Этот код выполняет несколько экземпляров и как этого избежать? - PullRequest
1 голос
/ 24 июня 2019

Предположим, у меня есть некоторый код, который выглядит следующим образом

Convert.hpp

#pragma once

#include <cassert>

class Converter
{
public:
  template <typename T>
  static inline void to_type(const char* bytes, T& val);
  static inline void to_int(const char* bytes, int& val);
};

#include "converter.inl"

Convert.inl

template <typename T>
void Converter::to_type(const char* bytes, T& value)
{
    auto numberOfBytes = sizeof(T);
    if (numberOfBytes == 8)
    {
        value = (T)(*(bytes + 3) << 40 | *(bytes + 3) << 32 | *(bytes + 3) << 24 | *(bytes + 2) << 16 | *(bytes + 1) << 8 | *bytes);
    }
    else if (numberOfBytes == 4)
    {
        value = (T)(*(bytes + 3) << 24 | *(bytes + 2) << 16 | *(bytes + 1) << 8 | *bytes);
    }
    else if (numberOfBytes == 2)
    {
        value = (T)(*(bytes + 1) << 8 | *bytes);
    }
    else {
        assert(false);
    }
}

void Converter::to_int(const char* bytes, int& value)
{
  to_type(bytes, value);
}

Userofconverter.hpp

#pragma once

bool isConverterUsed(const char* bytes);

Userofconverter.cpp

#include <iostream>

#include "converter.hpp"

bool isConverterUsed(const char* bytes)
{
  int myIntValue = 0;
  Converter::to_type(bytes, myIntValue);
  std::cout << "myIntValue: " << myIntValue << std::endl;
  return true;
}

Anotheruserofconverter.hpp

#pragma once

bool isConverterUsedAgain(const char* bytes);

Anotheruserofconverter.cpp

#include <iostream>

#include "converter.hpp"

bool isConverterUsedAgain(const char* bytes)
{
  int myIntValue = 0;
  Converter::to_type(bytes, myIntValue);
  std::cout << "myIntValue: " << myIntValue << std::endl;
  return true;
}

Этот код ничего не делает, кроме как помогает мне проиллюстрировать мою проблему. Когда я компилирую с g++ (Ubuntu 8.3.0-6ubuntu1~18.04) 8.3.0 (в WSL, если это важно как-то), я получаю следующий вывод

$g++ main.cpp userofconverter.cpp anotheruserofconverter.cpp
In file included from converter.hpp:13,
                 from userofconverter.cpp:3:
converter.inl: In static member function ‘static void Converter::to_type(const char*, T&)’:
converter.inl:7:31: warning: left shift count >= width of type [-Wshift-count-overflow]
   value = (T)(*(bytes + 3) << 40 | *(bytes + 3) << 32 | *(bytes + 3) << 24 | *(bytes + 2) << 16 | *(bytes + 1) << 8 | *bytes);
                               ^~
converter.inl:7:52: warning: left shift count >= width of type [-Wshift-count-overflow]
   value = (T)(*(bytes + 3) << 40 | *(bytes + 3) << 32 | *(bytes + 3) << 24 | *(bytes + 2) << 16 | *(bytes + 1) << 8 | *bytes);
                                                    ^~
converter.inl: In instantiation of ‘static void Converter::to_type(const char*, T&) [with T = int]’:
converter.inl:24:23:   required from here
converter.inl:7:28: warning: left shift count >= width of type [-Wshift-count-overflow]
   value = (T)(*(bytes + 3) << 40 | *(bytes + 3) << 32 | *(bytes + 3) << 24 | *(bytes + 2) << 16 | *(bytes + 1) << 8 | *bytes);
               ~~~~~~~~~~~~~^~~~~
converter.inl:7:49: warning: left shift count >= width of type [-Wshift-count-overflow]
   value = (T)(*(bytes + 3) << 40 | *(bytes + 3) << 32 | *(bytes + 3) << 24 | *(bytes + 2) << 16 | *(bytes + 1) << 8 | *bytes);
                                    ~~~~~~~~~~~~~^~~~~
In file included from converter.hpp:13,
                 from anotheruserofconverter.cpp:3:
converter.inl: In static member function ‘static void Converter::to_type(const char*, T&)’:
converter.inl:7:31: warning: left shift count >= width of type [-Wshift-count-overflow]
   value = (T)(*(bytes + 3) << 40 | *(bytes + 3) << 32 | *(bytes + 3) << 24 | *(bytes + 2) << 16 | *(bytes + 1) << 8 | *bytes);
                               ^~
converter.inl:7:52: warning: left shift count >= width of type [-Wshift-count-overflow]
   value = (T)(*(bytes + 3) << 40 | *(bytes + 3) << 32 | *(bytes + 3) << 24 | *(bytes + 2) << 16 | *(bytes + 1) << 8 | *bytes);
                                                    ^~
converter.inl: In instantiation of ‘static void Converter::to_type(const char*, T&) [with T = int]’:
converter.inl:24:23:   required from here
converter.inl:7:28: warning: left shift count >= width of type [-Wshift-count-overflow]
   value = (T)(*(bytes + 3) << 40 | *(bytes + 3) << 32 | *(bytes + 3) << 24 | *(bytes + 2) << 16 | *(bytes + 1) << 8 | *bytes);
               ~~~~~~~~~~~~~^~~~~
converter.inl:7:49: warning: left shift count >= width of type [-Wshift-count-overflow]
   value = (T)(*(bytes + 3) << 40 | *(bytes + 3) << 32 | *(bytes + 3) << 24 | *(bytes + 2) << 16 | *(bytes + 1) << 8 | *bytes);
                                    ~~~~~~~~~~~~~^~~~~

В выводе компиляции я вижу дважды это сообщение In instantiation of ‘static void Converter::to_type(const char*, T&) [with T = int]’

  1. Означает ли это, что функция Converter :: to_type фактически создается два раза?
  2. Если так, есть ли способ избежать множественных экземпляров?

Ответы [ 3 ]

2 голосов
/ 24 июня 2019

Шаблон будет скомпилирован дважды.Это связано с тем, что встроенные функции определены в заголовках, а заголовки не компилируются, поэтому каждый файл cpp должен компилировать свою собственную версию каждой встроенной функции, которую он использует, на тот случай, если никакой другой файл cpp не использует встроенную функцию.Однако, если встроенная функция встроена компилятором, это необходимо в любом случае, и если встроенная функция не встроена, компоновщик удалит дубликаты.

Вы можете создать явное создание экземпляра для Converter :: to_type в файле cpp, чтобы он не компилировался дважды.

// file Converter.h
#pragma once

#include <cassert>

class Converter
{
public:
  template <typename T>
  static inline void to_type(const char* bytes, T& val);
  ...
};
extern template void Converter::to_type<int>(const char* bytes, int& val);

...
// file Converter.cpp
#include "Converter.h"

template void Converter::to_type<int>(const char* bytes, int& val);
0 голосов
/ 24 июня 2019

Вы скомпилировали 3 файла cpp, g++ main.cpp userofconverter.cpp anotheruserofconverter.cpp, каждый файл cpp в командной строке будет генерировать Единицу перевода .

Каждая единица перевода будет #include "converter.hpp", потому что вы сказали это, и во время компиляции этих двух единиц перевода обе они заметили предупреждения и ошибки в converter.hpp, поэтому вы видите те же сообщения.

Да, это можно решить, например, вы можете скомпилировать один файл (например, main.cpp) и включить userofconverter.cpp и anotheruserofconverter.cpp, и он будет скомпилирован как одна единица перевода.

0 голосов
/ 24 июня 2019

Converter::to_type появляется несколько раз в сообщении об ошибке как часть трассировки экземпляра.Почему в конкретном экземпляре to_type есть две ошибки?Возможно, потому что вы не использовали constexpr numberOfBytes и if constexpr, поэтому весь код в to_type должен быть действительным и скомпилированным.Если if constexpr недоступен, вы все равно можете эмулировать его с помощью специализаций шаблонов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...