Можно ли в C ++ условно компилировать код, если типы (не) равны - PullRequest
0 голосов
/ 29 декабря 2018

В настоящее время у меня проблема с переносимостью кода с 64 (обратно) на 32 бита.Проблема в том, что метод класса перегружен для 64-битных платформ, что конфликтует с другой перегрузкой на 32-битных платформах.

Два метода выглядят так:

void myfunc(unsigned o);
void myfunc(size_t o);

On 32битовые архитектуры выглядят идентично компилятору и выдают некоторую ошибку.

Итак, вопрос в том, возможно ли сделать что-то вроде этого:

void myfunc(unsigned o);
#if typeid(unsigned) != typeid(size_t)
void myfunc(size_t o);
#endif

Мое текущее решение выглядит так:

void myfunc(unsigned o);
#if __WORDSIZE == 64
void myfunc(size_t o);
#endif

Но остается некоторое плохое предчувствие, что WORDSIZE не подходит лучше всего, потому что это не обязательно означает, что типы не совпадают.

РЕДАКТИРОВАТЬ: ОКВот проблемные строки 705 и 706, которые выдают ошибку при компиляции на 32-битном плече.https://github.com/ceph/ceph/blob/master/src/include/buffer.h#L705

Ответы [ 3 ]

0 голосов
/ 30 декабря 2018

Если базовая стандартная библиотека C поддерживает «Расширения с плавающей запятой, часть 1» (ИСО / МЭК TS 18661-1: 2014) , то у вас есть доступные макросы препроцессора, которые можно использовать для идентификацииразмеры типов:

#include<climits>
#include<cstdint>

void myfunc(unsigned o);
#if UINT_WIDTH != SIZE_WIDTH
void myfunc(size_t o);
#endif

Это поддерживается, например, glibc.Помните, что тест всегда завершается неудачей, если макросы не определены, т. Е. Если спецификация не реализована, поэтому вам, вероятно, следует также проверить это, то есть

#if UINT_WIDTH != SIZE_WIDTH || !defined(UINT_WIDTH) || !defined(SIZE_WIDTH)

Без таких макросов, определяемых реализацией, препроцессорне может быть использован для достижения того, что вы хотите, так как он фактически не знает о типах C или C ++.

Любое решение на уровне компиляции C ++ потребует от вас хотя бы некоторой модификации объявлений функций.

Я не считаю это решение особенно чистым, но ваше текущее решение также не является.Действительно, если, как я подозреваю, цель состоит в том, чтобы избежать определенных неявных преобразований, метод должен представлять собой шаблон с static_assert, ограничивающим тип соответствующим образом.


Редактировать:

Приведенный выше код работает как есть с текущими glibc и gcc, но я не уверен, технически ли это правильно.Это техническая спецификация, расширяющая C11, а не C ++.Я не знаю, как и включает ли C ++ их, или они будут считаться расширениями, определяемыми реализацией.

Также согласно спецификации макросы должны быть определены, только если вы

#define __STDC_WANT_IEC_60559_BFP_EXT__

до первого #include<stdint.h> или #include<limits.h>.При компиляции в режиме C GCC с glibc действительно требует этого.

Можно ли проверить, реализована ли спецификация, сравнив макрос __STDC_IEC_60559_BFP__ с 201ymmL.Однако GCC с glibc, похоже, не устанавливает этот макрос, и в документации отмечается, что поддержка спецификации является лишь частичной.

Вероятно, вы должны по крайней мере убедиться, что UINT_WIDTH и SIZE_WIDTH установлены, прежде чем доверятьсравнение сделано выше.Если это не так, например, из-за того, что спецификация не поддерживается, всегда будет оцениваться как 0 != 0, то есть false.

0 голосов
/ 30 декабря 2018

Вы можете использовать std::enable_if для этого:

#include <type_traits>

struct S {
      void advance(unsigned o);
      std::enable_if<!std::is_same<unsigned, std::size_t>::value>::type
      advance(std::size_t o) { advance(static_cast<unsigned>(o)); }
};

Хотя, как уже отмечали другие, я отказался бы от варианта unsigned и оставил бы только std::size_t вариант.

0 голосов
/ 30 декабря 2018

Это может быть вариант с использованием шаблонов:

#include <iostream>

class A {
public:
    template<typename T>
    std::enable_if_t<std::is_same<T, int>::value || 
    std::is_same<T, unsigned>::value ||
    std::is_same<T, std::size_t>::value >
    advance(T o) {
        std::cout << "s" << std::endl;
        A::advance<unsigned>(static_cast<unsigned>(o));
    }
};

template<>
    void A::advance(int o) = delete;

template<>
    void A::advance(unsigned o) {
        std::cout << "u" << std::endl;
    }

int main()
{
  A a;

  unsigned x;
  std::size_t y;
  int z;
  char p;

  a.advance(x);
  a.advance(y);
  //a.advance(z);
  //a.advance(p);

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