如果类型(不)相等,C++是否有条件编译代码?

如果类型(不)相等,C++是否有条件编译代码?,c++,preprocessor,overloading,C++,Preprocessor,Overloading,目前,我在从64位到32位的代码可移植性方面存在问题。问题是,对于64位平台,类的一个方法重载,这与32位平台上的另一个重载冲突 这两种方法如下所示: void myfunc(unsigned o); void myfunc(size_t o); void myfunc(unsigned o); #if typeid(unsigned) != typeid(size_t) void myfunc(size_t o); #endif void myfunc(unsigned o); #if _

目前,我在从64位到32位的代码可移植性方面存在问题。问题是,对于64位平台,类的一个方法重载,这与32位平台上的另一个重载冲突

这两种方法如下所示:

void myfunc(unsigned o);
void myfunc(size_t o);
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
在32位体系结构上,它们看起来与编译器相同,并抛出一些错误

所以,问题是,有没有可能这样做:

void myfunc(unsigned o);
void myfunc(size_t o);
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
我当前的解决方案如下所示:

void myfunc(unsigned o);
void myfunc(size_t o);
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
但是还有一些不好的感觉,字号不是最合适的,因为它不一定意味着类型不一样

编辑:好的,这里是有问题的第705行和第706行,在32位arm上编译时会产生错误。

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

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

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

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

如果基础C标准库支持,则可以使用预处理器宏来标识类型的大小:

#include<climits>
#include<cstdint>

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

没有这样的实现定义宏,预处理器不能用于实现你想要的,因为它实际上不知道C或C++类型。 <> > C++编译级别的任何解决方案都需要至少修改函数声明。

我不认为这个解决方案特别干净,但是你目前的解决方案也不是。实际上,如果正如我所怀疑的那样,目标是避免某些隐式转换,那么该方法应该是一个带有静态断言的模板,并根据需要限制类型

编辑:

上面的代码与当前的glibc和gcc一样工作,但我不确定这在技术上是否是正确的行为。这是一个扩展C11,而不是C++的技术规范。我不知道C++如何或是否包含这些,或者它们是否被认为是实现定义的扩展。 此外,根据规范,只有在以下情况下才应定义宏:

#define __STDC_WANT_IEC_60559_BFP_EXT__
在第一个include或include之前。当使用glibc在C模式下编译时,GCC确实需要这样做

通过将宏u STDC_IEC_60559_BFP_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。然而,GCC和glibc似乎并没有设置这个宏,文档中指出,对该规范的支持只是部分


在信任上面的比较之前,您可能至少应该确保设置了UINT_WIDTH和SIZE_WIDTH。如果不支持,例如,由于不支持规范,is将始终计算为0!=0,即false。

如果基础C标准库支持,则可以使用预处理器宏来标识类型的大小:

#include<climits>
#include<cstdint>

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

没有这样的实现定义宏,预处理器不能用于实现你想要的,因为它实际上不知道C或C++类型。 <> > C++编译级别的任何解决方案都需要至少修改函数声明。

我不认为这个解决方案特别干净,但是你目前的解决方案也不是。实际上,如果正如我所怀疑的那样,目标是避免某些隐式转换,那么该方法应该是一个带有静态断言的模板,并根据需要限制类型

编辑:

上面的代码与当前的glibc和gcc一样工作,但我不确定这在技术上是否是正确的行为。这是一个扩展C11,而不是C++的技术规范。我不知道C++如何或是否包含这些,或者它们是否被认为是实现定义的扩展。 此外,根据规范,只有在以下情况下才应定义宏:

#define __STDC_WANT_IEC_60559_BFP_EXT__
在第一个include或include之前。当使用glibc在C模式下编译时,GCC确实需要这样做

通过将宏u STDC_IEC_60559_BFP_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。然而,GCC和glibc似乎并没有设置这个宏,文档中指出,对该规范的支持只是部分

在信任上面的比较之前,您可能至少应该确保设置了UINT_WIDTH和SIZE_WIDTH。如果不支持,例如,由于不支持规范,is将始终计算为0!=0,即false。

您可以使用:

#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)); }
};
不过,正如其他人已经指出的那样,我会放弃无符号变量,只保留std::size\u t变量。

您可以使用它:

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

但是,正如其他人已经指出的那样,我会放弃无符号变量,只保留std::size\u t变量。

如果您试图重载32位和64位整数,为什么不使用uint32\u t和uint64\u t重载?它们的宽度不会因平台而异。我还没有尝试过这个方法,但我认为sizeofunsigned==nn可能会起作用。你有反对意见吗?否则,您可以在当前解决方案中将_WORDSIZE重命名为_BITSIZE或其他名称。我已经有了相同的想法,

但是sizeof不包括signedness:-您不需要它来简单地将重载强制转换为unsigned并调用另一个变量。您可以简单地删除它。如果您试图重载32位和64位整数,为什么不使用uint32\u t和uint64\u t重载?它们的宽度不会因平台而异。我还没有尝试过这个方法,但我认为sizeofunsigned==nn可能会起作用。你有反对意见吗?否则,您可以在当前解决方案中将_WORDSIZE重命名为_BITSIZE或其他名称。我已经有了相同的想法,但sizeof不包括签名:-您不需要它,重载只需转换为unsigned并调用另一个变量。你可以简单地删除它。这不是一个完美的解决方案,但比我使用的WORDSIZE脏补丁要好得多。“我认为这是避免重重构的最佳选择。”themole再次修改了答案。如果没有实现规范,确保测试成功可能对您的案例很重要。这不是一个完美的解决方案,但比我使用的WORDSIZE脏补丁要好得多。“我认为这是避免重重构的最佳选择。”themole再次修改了答案。对于您的案例来说,如果没有实现规范,确保测试成功可能很重要。我喜欢这个解决方案,并且我更喜欢它用于我自己的代码,因为它是一个干净的代码解决方案。但它会在一些现有的和开发良好的代码库中引入太多的重新构造,这些代码库主要在64位机器上运行,而这些机器不会受到此错误的影响。尽管如此,还是要感谢您的示例代码。我喜欢这个解决方案,而且我更喜欢将它用于我自己的代码,因为它是一个干净的代码解决方案。但它会在一些现有的和开发良好的代码库中引入太多的重新构造,这些代码库主要在64位机器上运行,而这些机器不会受到此错误的影响。尽管如此,还是要感谢这个很好的示例代码。如果条件不满足,这将给出一个硬错误。如果只在模板替换期间正常工作,并且OP似乎不想更改函数签名,则启用_。如果条件不满足,则会出现硬错误。如果只在模板替换期间正常工作并且OP似乎不想更改函数签名,则启用_。