C++ 在某个命名空间中定义方法时在全局命名空间中声明?

C++ 在某个命名空间中定义方法时在全局命名空间中声明?,c++,visual-studio,templates,namespaces,C++,Visual Studio,Templates,Namespaces,“我的代码”包含两部分—命名空间内的类模板test,My,以及全局命名空间中的函数frobnite。类模板希望在其方法之一中使用此函数,我希望在其用法附近声明它: namespace my { template <class T> struct test { void do_stuff(T& i) { void frobnicate(T&); frobnicate(

“我的代码”包含两部分—命名空间内的类模板
test
My
,以及全局命名空间中的函数
frobnite
。类模板希望在其方法之一中使用此函数,我希望在其用法附近声明它:

namespace my
{
    template <class T>
    struct test
    {
        void do_stuff(T& i)
        {
            void frobnicate(T&);
            frobnicate(i);

            // more code here
        }
    };
}

struct SomeClass {};

void frobnicate(SomeClass& i)
{
    // some code here
}

int main()
{
    my::test<SomeClass> t;
    SomeClass object;
    t.do_stuff(object);
}
名称空间我的
{
模板
结构测试
{
无效do_材料(T&i)
{
无效泡沫(T&);
泡沫(i);
//这里有更多代码
}
};
}
结构SomeClass{};
无效副本(某些类别和i)
{
//这里有一些代码
}
int main()
{
我的::测试t;
类对象;
t、 做某事(对象);
}
这在MS Visual Studio 2017中有效,因为存在一个bug(已描述),因为Visual Studio在全局命名空间中声明函数,而根据标准,此类声明在当前命名空间中声明函数

template <class T>
void frobnicate(T&);

namespace my {

template <class T>
struct test
{
    void do_stuff(T& i)
    {
        frobnicate(i);
        // more code here
    }
};
}  // close my namespace
然而,gcc有理由抱怨:

。。。对“my::frobNote(SomeClass&)”的未定义引用

我可以让它在gcc或任何其他符合标准的编译器中工作吗



如果我在声明模板
test
之前声明了
frobnite
,那么代码就可以工作了。但是,在我的实际代码中,这两部分代码位于不相关的头文件中,我希望我的代码能够正常工作,而不考虑
#include
s的顺序,如果可能的话。

我认为您可以简单地在单独的文件中声明
Frobnite
,并在创建名称空间
my
之前包含它。或者您可以将函数声明为宏,并在同一文件中定义。然后您可以在
my
中的
do\u stuff
中调用
frobnite


否则您不能调用未定义的函数。

我认为您可以简单地在单独的文件中声明
Frobnite
,并在创建命名空间
my
之前将其包含在内。或者您可以将函数声明为宏,并在同一文件中定义。然后您可以在
my
中的
do\u stuff
中调用
frobnite


否则,您不能调用未定义的函数。

只需将您的
frobNote
函数向前声明为命名空间之前的模板

template <class T>
void frobnicate(T&);

namespace my {

template <class T>
struct test
{
    void do_stuff(T& i)
    {
        frobnicate(i);
        // more code here
    }
};
}  // close my namespace
模板
无效泡沫(T&);
名称空间我的{
模板
结构测试
{
无效do_材料(T&i)
{
泡沫(i);
//这里有更多代码
}
};
}//关闭我的命名空间

只需向前声明
frobnate
函数作为命名空间之前的模板

template <class T>
void frobnicate(T&);

namespace my {

template <class T>
struct test
{
    void do_stuff(T& i)
    {
        frobnicate(i);
        // more code here
    }
};
}  // close my namespace
模板
无效泡沫(T&);
名称空间我的{
模板
结构测试
{
无效do_材料(T&i)
{
泡沫(i);
//这里有更多代码
}
};
}//关闭我的命名空间

解决方案似乎相当明显:将
frobnite()
的声明放在第三个头文件中,使用
ifndef/define
保护,并在打开名称空间声明之前,将此头文件包含在两个现有头文件的开头。不知道为什么这个看似简单的典型解决方案对您不起作用。作为最后的手段,它肯定会起作用。这个解决方案的问题是,它使定义模板的头文件依赖于定义
SomeClass
的不相关头文件。这种依赖关系在我的代码中没有意义,特别是当我有几个
SomeClass
e模板应该为其工作时。这就是“转发声明”的用途。新的头文件不需要包含其他整个头文件。它只需要包含“
类SomeClass;void frobnite(SomeClass&);
”。故事的结尾。解决方案似乎相当明显:将
frobnite()
的声明放在第三个头文件中,使用
ifndef/define
guards,并将此头文件包含在两个现有头文件的开头,然后再打开名称空间声明。不知道为什么这个看似简单的典型解决方案对您不起作用。作为最后的手段,它肯定会起作用。这个解决方案的问题是,它使定义模板的头文件依赖于定义
SomeClass
的不相关头文件。这种依赖关系在我的代码中没有意义,特别是当我有几个
SomeClass
e模板应该为其工作时。这就是“转发声明”的用途。新的头文件不需要包含其他整个头文件。它只需要包含“
类SomeClass;void frobnite(SomeClass&);
”。故事结束。在frobinate中使用
T const volatile&
以避免它比ADL one更受欢迎?不知道你的意思,因为我不控制
Frobnite
接口,那么可能“void do_stuff(T&I){使用::Frobnite;Frobnite(I);}`更好吗?在frobinate中使用
T const volatile&
以避免它比ADL one更受欢迎?不知道你的意思,因为我不控制
Frobnite
接口,那么“void do_stuff(T&I){using::Frobnite;Frobnite(I);}更好吗?