如果类型(不)相等,在C ++中是否可以有条件地编译代码

时间:2018-12-29 20:23:36

标签: c++ preprocessor overloading

目前,我对代码从64(后退)到32位的可移植性有疑问。问题是,对于64位平台,类的方法已重载,而与32位平台上的另一重载冲突。

这两种方法如下:

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

在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 :(得分:3)

如果基础的C标准库支持"Floating-point extensions part 1" (ISO/IEC 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模式下进行编译时,使用glibc的GCC实际上确实需要这样做。

是否可以通过比较宏__STDC_IEC_60559_BFP__201ymmL来检查是否实现了规范。但是,带有glibc的GCC似乎没有设置此宏,并且文档指出对规范的支持只是部分的。

在信任上述比较之前,可能至少应确保已设置UINT_WIDTHSIZE_WIDTH。如果不是,例如因为不支持该规范,所以它将始终评估为0 != 0,即false

答案 1 :(得分:1)

这可能是使用模板的选项:

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

答案 2 :(得分:0)

您可以使用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变体。