粘贴“::”和“Foo”不会提供有效的预处理令牌

时间:2014-12-08 15:23:01

标签: c++ macros preprocessor-directive

我想将MyNamespace ::附加到宏定义的函数:

#define transFunc(func)                                                    \
dimensionedScalar func(const dimensionedScalar& ds)                        \
{                                                                          \
    if (!ds.dimensions().dimensionless())                                  \
    {                                                                      \
        FatalErrorIn(#func "(const dimensionedScalar& ds)")                \
            << "ds not dimensionless"                                      \
            << abort(FatalError);                                          \
    }                                                                      \
                                                                           \
    return dimensionedScalar                                               \
    (                                                                      \
        #func "(" + ds.name() + ')',                                       \
        dimless,                                                           \
        MyNameSpace::##func(ds.value())                                                 \
    );                  

                                               \

}

但是当我打电话时

transFunc(Foo)

编译器抛出以下错误:

  

粘贴“::”和“Foo”不会提供有效的预处理令牌

我上面连接令牌的方式有什么问题?

4 个答案:

答案 0 :(得分:6)

##用于将两个令牌组合在一起以制作单个令牌。因此func##1之类的东西会扩展为单个标记func1

在此处使用它时,它会尝试将::Foo组合在一起以制作单个标记::Foo。正如错误所说,这不是有效的令牌。你不想在这里有一个令牌;你只想将两个令牌分开:

MyNameSpace::func(ds.value())

答案 1 :(得分:1)

##适用于宏,它并不适用于常规代码。

您可以按照以下方式执行此操作:

#define ADD_NAMESPACE(NS,FUNC) NS##::##FUNC

现在您可以像这样使用它:

ADD_NAMESPACE(std,cout)<<x1<<ADD_NAMESPACE(std,endl);

但你不能这样做:

std ## :: ## cout<<std ## :: ## endl;

你这样做:

std::cout<<std::endl;

修改

此示例适用于gcc版本4.8.5 20150623(Red Hat 4.8.5-16)(GCC):

#include <iostream>
#define ADD_NAMESPACE(NS,FUNC) NS##::##FUNC
int main()
{
  ADD_NAMESPACE(std,cout)<<"hello world!"<<ADD_NAMESPACE(std,endl);
  return 0;
}

答案 2 :(得分:1)

正如其他人所说,##在编译的标记化阶段(或之后)连接两个标记:

a##b => (a) ## (b) => (ab)
( possibly invalid, like (::bar) instead of (::), (bar) )

注意,这不会通过令牌化程序发回连接的令牌标识符,编译阶段已经完成。可能搞砸的是,这些现在是令牌,而不是原始字符串了

当我(来到派对上)来这里寻找相同的信息时,如果事情仍然没有意义,这里是一个foo.cpp示例:

#define FOO(a) Something::a

int main()
{
        FOO( bar );
        FOO( cat );

        return 0;
}

gcc -E foo.cpp 生成

# 1 "foo.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "foo.cpp"



int main()
{
 Something::bar;
 Something::cat;

 return 0;
}

答案 3 :(得分:0)

给你的函数添加一个前缀怎么样,比如'_':

dimensionedScalar _##func(const dimensionedScalar& ds)                        

然后你可以将 '_' 与 func 连接起来:

MyNameSpace::_##func(ds.value())