Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ GCC中的模板不';我看不到在它之后,但在实例化之前声明的函数_C++_Templates_Gcc - Fatal编程技术网

C++ GCC中的模板不';我看不到在它之后,但在实例化之前声明的函数

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

以下是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 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;
}