C++ GCC中的模板不';我看不到在它之后,但在实例化之前声明的函数
以下是Visual Studio编译得很好的内容:C++ GCC中的模板不';我看不到在它之后,但在实例化之前声明的函数,c++,templates,gcc,C++,Templates,Gcc,以下是Visual Studio编译得很好的内容: #include <string> #include <vector> template <typename T> T read() { T value; read(value); // gcc compile error here return value; } void read(std::string& str) { } template <typename
#include <string>
#include <vector>
template <typename T>
T read()
{
T value;
read(value); // gcc compile error here
return value;
}
void read(std::string& str)
{
}
template <typename T>
void read(std::vector<T>& vec)
{
}
int main(int argc, char** argv) {
read<std::string>();
read<std::vector<int>>();
read<std::vector<float>>();
return 0;
}
#包括
#包括
模板
T read()
{
T值;
读取(值);//此处gcc编译错误
返回值;
}
无效读取(标准::字符串和字符串)
{
}
模板
无效读取(标准::向量和向量)
{
}
int main(int argc,字符**argv){
read();
read();
read();
返回0;
}
但GCC生成编译错误:调用没有匹配函数
我找到了唯一适合我的解决方案,在read()之前声明模板函数read(T&):
模板
无效读取(T&);
模板
T read()
{
T值;
读取(值);
返回值;
}
模板
无效读取(标准::字符串和字符串)
{
}
//模板
//无效读取(标准::向量和向量)
//{
//}
但我不知道如何将模板函数放入其中
有没有更好的方法让gcc看到在使用它们的模板之后声明的函数,但在模板实例化之前声明的函数?您并没有仅仅交换顺序。您更改了以下内容:
template <typename T>
void read(std::vector<T>& vec)
{}
模板
无效读取(标准::向量和向量)
{}
为此:
template <typename T>
void read(T&);
模板
无效读取(T&);
这两个完全不同!在前一种情况下,可能无法进行演绎。我只是将声明放在前面,其余的编译。我不是语言律师,但我相信gcc在这里是正确的。对代码进行一些小的修改,使其在编译时不会出现警告
//Forward declarations needed:
void read(std::string& str);
template <typename T> void read(std::vector<T>& vec);
// mostly your original code
template <typename T>
T read()
{
T value;
read(value); // gcc compile error here
return value;
}
void read(std::string& )
{
}
template <typename T>
void read(std::vector<T>& )
{
}
int main() {
read<std::string>();
read<std::vector<int>>();
read<std::vector<float>>();
return 0;
}
//需要转发声明:
无效读取(std::string和str);
模板无效读取(标准::矢量和矢量);
//主要是您的原始代码
模板
T read()
{
T值;
读取(值);//此处gcc编译错误
返回值;
}
无效读取(标准::字符串&)
{
}
模板
无效读取(标准::向量&)
{
}
int main(){
read();
read();
read();
返回0;
}
仔细考虑您的声明顺序:
template <typename T>
T read()
{
T value;
read(value); // gcc compile error here
return value;
}
void read(std::string& str) {}
template <typename T>
void read(std::vector<T>& vec) {}
。定义显然也是一种声明,因此将整个定义放在其中也会起作用(如果后两个重载的定义不依赖于该函数模板!)。要允许以后进行覆盖(无需转发),可以为名称查找引入标记(在声明读取的命名空间中):
#include <string>
#include <vector>
namespace Read {
template <typename T>
struct Tag {};
template <typename T>
T read()
{
T value;
read(Tag<T>(), value);
return value;
}
} // namespace Read
template <typename T>
T read()
{
return Read::read<T>();
}
namespace Read {
void read(Tag<std::string>, std::string& str)
{
}
template <typename T>
void read(Tag<std::vector<T>>, std::vector<T>& vec)
{
}
} // namespace Read
int main(int argc, char** argv) {
read<std::string>();
read<std::vector<int>>();
read<std::vector<float>>();
return 0;
}
#包括
#包括
名称空间读取{
模板
结构标记{};
模板
T read()
{
T值;
读取(标记(),值);
返回值;
}
}//名称空间读取
模板
T read()
{
返回Read::Read();
}
名称空间读取{
无效读取(标记、标准::字符串和字符串)
{
}
模板
无效读取(标记、标准::向量和向量)
{
}
}//名称空间读取
int main(int argc,字符**argv){
read();
read();
read();
返回0;
}
(注意:它也在全局名称空间中工作)为哪个调用编译错误?如果VS编译它,那么这可能是它的非标准扩展,允许临时程序绑定到非
const
引用,尽管我无法立即理解为什么这段代码会尝试这样做。编译错误适用于所有调用。您的两个程序并不等效。您所做的不仅仅是交换定义的顺序。请在Coliru上提供一个示例。尝试在main
之前声明此示例:template struct X:B{}
然后调用read()
,对于向量也是如此。但是:当你的代码审查失败时,不要怪我:这不是VS中断的两阶段查找的另一个影响吗?ADL(在第二阶段从POI执行)在第一个代码块中找不到read
。我没有交换任何东西。我在start中添加了read(T&)的模板声明,以使read()在read()之后看到此声明的所有专门化。但是read(std::vector&)不适合这个解决方案,因为它是模板,所以我把它注释掉了。@GLaz:你看不出你引入了一个模板void read(t&)
,它在你的第一个代码中不存在吗?谢谢,这是一个非常明显的解决方案,但是所有这些函数都在不同的文件中,并且包含在代码的任何地方。所以,我需要为read的所有变体(SomeClass&)提供一些通用的声明。那么,为什么不将声明放在一个通用头中,其余的放在其他地方呢?嘿,投票人能给出一些评论吗?出什么事了?让我也从你们的知识中学到:-)我的答案和哥伦布的答案使用相同的东西,哥伦布的答案是后来的答案,但被升级了。。。Nice:-)问题不在std:,因为void read(int&i)也不编译。我还有数百个read(…)重载,因此无法在开始时声明所有重载。@GLaz基本类型的关联命名空间集为空(因此不包括全局命名空间)。基本上是一样的,谢谢。但也许有一种方法可以实现向量“模板化”专门化(请参阅我的第二个代码快照和注释掉的代码),因为什么时候声明顺序才重要呢?非常感谢。在更新中查看基于您想法的解决方案。
void read(std::string& str);
template <typename T>
void read(std::vector<T>& vec);
template <typename T>
T read()
{
T value;
read(value); // gcc compile error here
return value;
}
#include <string>
#include <vector>
namespace Read {
template <typename T>
struct Tag {};
template <typename T>
T read()
{
T value;
read(Tag<T>(), value);
return value;
}
} // namespace Read
template <typename T>
T read()
{
return Read::read<T>();
}
namespace Read {
void read(Tag<std::string>, std::string& str)
{
}
template <typename T>
void read(Tag<std::vector<T>>, std::vector<T>& vec)
{
}
} // namespace Read
int main(int argc, char** argv) {
read<std::string>();
read<std::vector<int>>();
read<std::vector<float>>();
return 0;
}