简体   繁体   English

C ++:使用#if std :: is_fundamental <T> :: MSVC 2010中条件编译的值

[英]C++: Use #if std::is_fundamental<T>::value for conditional compilation in MSVC 2010

In my template I need to have different code parts based on whether the typename is a fundamental type or not. 在我的模板中,根据typename是否为基本类型,我需要具有不同的代码部分。

Compiling this code gives a C4067 in MSVC (unexpected tokens following preprocessor directive - expected a newline): 编译此代码将得到MSVC中的C4067(预处理指令后出现意外令牌-预期换行):

template <typename T>
void MyClass<T>::foo()
{
// ... some code here
#if std::is_fundamental<T>::value
    if(m_buf[j] < m_buf[idx_min])
        idx_min = j;
#else
    const ASSortable& curr = dynamic_cast<ASSortable&>(m_buf[j]);
    const ASSortable& curr_min = dynamic_cast<ASSortable&>(m_buf[idx_min]);
    // error checking removed for simplicity
    if(curr.before(curr_min))
        idx_min = j;
}
#endif

The template is to work with both primitive and my own (derived from ASSortable) data types and the error is thrown from template instantiation code: 该模板可同时使用原始数据类型和我自己的数据类型(从ASSortable派生),并且从模板实例化代码引发错误:

template class MyClass<char>;

Trying to modify the precompiler expression to this didn't work either: 尝试将预编译器表达式修改为此不起作用:

#if std::is_fundamental<T>::value == true

and produces the same exact warning. 并产生完全相同的警告

Any ideas how to make this code warning-free? 任何想法如何使此代码无警告?

Edit Another thing that comes to mind is to convert this into a run-time check and live with the "constant if expression" warning... Is there really no way to do this elegantly in a single function with no specializations and no extra bloat? 编辑想到的另一件事是将其转换为运行时检查,并带有“如果表达式为常数的警告”警告..​​.真的没有办法在没有专门化且没有额外膨胀的单个函数中优雅地完成此操作?

Edit #2 So the way I solved this (which was obvious, but somehow escaped me...) was to define a bool ASSortable::operator<(const ASSortable& _o) const {return this->before(_o);}; 编辑#2因此,我解决此问题的方法(很明显,但是以某种方式使我逃脱了……)是定义一个bool ASSortable::operator<(const ASSortable& _o) const {return this->before(_o);}; which does the job and makes the code clean (once again). 这可以完成工作并使代码干净(再次)。

No more if s or #ifdef s or any similar clutter in my code! if没有s或#ifdef或我的代码中任何类似的混乱情况!

Can't believe I even asked that question as it had such an obvious and simple answer :( 我什至不敢问这个问题,因为它有这么明显和简单的答案:(

The common pattern to solve that issue is moving the function to a base class that is specialized and abusing inheritance to bring it to your scope: 解决该问题的常用模式是将函数移至专门的基类,并滥用继承将其带入您的范围:

template <typename T, bool is_fundamental>
struct Foo_impl {
   void foo() {
   }
};
template <typename T>
struct Foo_impl<T,true>
{
   void foo() {              // is fundamental version
   }
};
template <typename T>
class Foo : public Foo_impl<T, std::is_fundamental_type<T>::value> {
   // ...
};

Another approach would be to implement those as private functions in your class and dispatch to them internally from foo based on the trait. 另一种方法是将这些函数实现为您的类中的私有函数,并根据特征从foo内部对其进行调度。 This is really simple and a cleaner solution, but fails if one of the two versions of the foo_impl will not compile. 这确实很简单,而且是一种更干净的解决方案,但是如果无法编译foo_impl的两个版本之一,则失败。 In that case you can use, as others have suggested a template member function to resolve, but I would still offer the non-templated foo as the public interface, forwarding to a private foo_impl template. 在那种情况下,您可以使用,因为其他人建议使用模板成员函数来解决, 但是我仍然会提供非模板化的foo作为公共接口,转发到私有foo_impl模板。 The reason is that the template in there is an implementation detail to hack conditional compilation, not part of the interface. 原因是template中有一个实现细节, 可用破解条件编译,而不是接口的一部分。 You don't want user code calling that member function with different template arguments than the type of your own class. 您不希望用户代码使用与您自己的类的类型不同的模板参数来调用该成员函数。 Borrowing from pmr's answer: 从pmr的答案中借用:

template <typename T>
struct Foo
{
  template <typename U = T, 
            typename std::enable_if< 
              std::is_fundamental<U>::value, int >::type* _ = 0
           >
  void foo() {
    std::cout << "is fundamental" << std::endl;
  }
//...

That solution allows user code like: 该解决方案允许用户代码如下:

Foo<int> f;
f.foo<std::string>();

Which will instantiate a function that you don't need nor want, and will execute the logic that you don't want. 这将实例化您不需要或不需要的功能,并执行您不需要的逻辑。 Even if users don't try to fool your class, the fact that is a template in the interface might be confusing and make users think that it is possible to call it for different types. 即使用户不试图愚弄您的类,作为界面模板的事实也可能使您感到困惑,并使用户认为可以为不同类型调用它。

Preproccessor is run at an early stage of compilation, before the compiler analyzes the types and knows the meaning of std::is_fundamental<T>::value , hence it cannot work this way. 在编译器分析类型并了解std::is_fundamental<T>::value的含义之前,Preproccessor在编译的早期阶段运行,因此它不能以这种方式工作。

Instead, use specialization: 而是使用专门化:

template<bool> void f();

template<> void f<true>() {
    if(m_buf[j] < m_buf[idx_min])
        idx_min = j;
}

template<> void f<false>() {
    const ASSortable& curr = dynamic_cast<ASSortable&>(m_buf[j]);
    const ASSortable& curr_min = dynamic_cast<ASSortable&>(m_buf[idx_min]);
    // error checking removed for simplicity
    if(curr.before(curr_min))
        idx_min = j;
}

template <typename T>
void MyClass<T>::foo()
{
// ... some code here
    f<std::is_fundamental<T>::value>();
}

EDIT: You're likely to need to make f a member function, however it's not directly possible since MyClass<T> is a non-specialized template. 编辑:您可能需要使f为成员函数,但是由于MyClass<T>是非专业模板,因此这不可能直接实现。 You could make f a global which delegates the call to the correct member of MyClass . 您可以将f为全局变量,以将调用委派给MyClass的正确成员。 However, there is another approach. 但是,还有另一种方法。

Using overloading, this becomes: 使用重载,它将变为:

void MyClass<T>::f(const true_type&) {
    if(m_buf[j] < m_buf[idx_min])
        idx_min = j;
}

void MyClass<T>::f(const false_type&) {
    const ASSortable& curr = dynamic_cast<ASSortable&>(m_buf[j]);
    const ASSortable& curr_min = dynamic_cast<ASSortable&>(m_buf[idx_min]);
    // error checking removed for simplicity
    if(curr.before(curr_min))
        idx_min = j;
}

template <typename T>
void MyClass<T>::foo()
{
// ... some code here
    f(std::is_fundamental<T>::type());
}

You are mixing up states of compilation. 您正在混淆编译状态。 The preprocessor is run before the actual compiler and has no knowledge of types or templates. 预处理程序在实际的编译器之前运行,并且不了解类型或模板。 It just performs (very) sophisticated text substitution. 它只是执行(非常)复杂的文本替换。

There is nothing such as static if 1 in current C++, so you have to resort to a different method to enable conditional compilation. 在当前的C ++中,没有什么是static if 1 ,那么您必须诉诸另一种方法来启用条件编译。 For functions I would prefer enable_if . 对于函数,我更喜欢enable_if

#include <type_traits>
#include <iostream>

template <typename T>
struct Foo
{
  template <typename U = T, 
            typename std::enable_if< 
              std::is_fundamental<U>::value, int >::type = 0
           >
  void foo() {
    std::cout << "is fundamental" << std::endl;
  }

  template <typename U = T, 
            typename std::enable_if< 
              !(std::is_fundamental<U>::value), int >::type = 0
           >
  void foo() {
    std::cout << "is not fundamental" << std::endl;
  }
};


struct x {};

int main()
{
  Foo<int> f; f.foo();
  Foo<x> f2; f2.foo();
  return 0;
}

1 References: 1参考:

Video : Static if presented by Alexandrescu in Going Native. 视频 :静态(如果由Alexandrescu在Going Native中呈现)。

n3322 : Walter E. Brown's proposal for static if n3322 :Walter E. Brown提出的static if

n3329 : Sutter, Bright and Alexandrescu's proposal for static if n3329 :Sutter,Bright和Alexandrescu提出的static if

It's pretty much what it says, you can't use :: in preprocessor directives. 它的含义大致相同,您不能在预处理程序指令中使用:: Actually, the only thing you can use after #if is a constant-expression that is defined before the compile-time. 实际上,在#if之后唯一可以使用的是在编译时定义的常量表达式。 You can find some info here 你可以在这里找到一些信息

std::is_fundamental<T>::value == true cannot be used at pre-processing time. std::is_fundamental<T>::value == true不能在预处理时使用。 I guess you would have to use some SFINAE trick with std::enable_if: 我猜您将不得不在std :: enable_if中使用一些SFINAE技巧:

template <typename T>
typename std::enable_if<std::is_fundamental<T>::value, void>::type 
MyClass<T>::foo()
{
    // ... some code here

    if(m_buf[j] < m_buf[idx_min])
        idx_min = j;
}


template <typename T>
typename std::enable_if<!std::is_fundamental<T>::value, void>::type 
MyClass<T>::foo()
{
    // ... some code here

    const ASSortable& curr = dynamic_cast<ASSortable&>(m_buf[j]);
    const ASSortable& curr_min = dynamic_cast<ASSortable&>(m_buf[idx_min]);
    // error checking removed for simplicity
    if(curr.before(curr_min))
        idx_min = j;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM