- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
假设我正在尝试创建我自己的 boost::filesystem::path 实现,使用 Curiously Recurring Template Pattern :
(为简洁起见,给出的代码不完整,但在使用 GCC 4.8.4 使用“g++ -std=c++11 -o mypath ./mypath.cpp
”编译时会出现所述问题)
我的路径.hpp:
#ifndef MYPATH_HPP
#define MYPATH_HPP
#include <string>
#include <vector>
namespace my {
template <class T>
class PathBase
{
public:
PathBase();
PathBase(std::string const& p);
std::string String() const;
bool IsSeparator(char c) const;
std::string Separators() const;
typedef std::vector<std::string> pathvec;
protected:
pathvec _path;
private:
virtual std::string _separators() const =0;
};
class Path : public PathBase<Path>
{
public:
Path();
Path(std::string const& p);
private:
virtual std::string _separators() const final;
};
} // namespace 'my'
#endif // MYPATH_HPP
我的路径.cpp:
#include "mypath.hpp"
namespace my {
//////////template class PathBase<Path>;
template<>
bool PathBase<Path>::IsSeparator(char c) const
{
return (Separators().find(c) != std::string::npos);
}
template <>
std::string PathBase<Path>::Separators() const
{
return _separators();
}
} // namespace
int main(int argc, char** argv)
{
return 0;
}
当然我发现编写的代码无法编译,因为我明确特化了Separators()
在 IsSeparator()
之后已隐式实例化它。但我并不是特别想玩打地鼠游戏,试图让我的所有方法都井井有条。
在研究关于 SO 的类似问题时,我发现这个 accepted answer其中一位建议我只需声明我的专业就可以巧妙地解决这个问题。但是……
template class PathBase<Path>;
mypath.cpp 中的行对问题没有影响,并且class Path : public PathBase<Path> { ... }
声明了显式特化。声明。 我的显式声明到底需要是什么样子?
最佳答案
让我们先解决这些问题:
template class PathBase<Path>;
不声明明确的特化;它是一个显式实例化定义。您要求编译器实例化 PathBase<Path>
以及它具有定义的所有成员,基于您当时提供的定义。在这种特定情况下,它确实没有任何区别。
显式特化的声明看起来像template<> class PathBase<Path>;
,但这也不是你想要的;见下文。
使用PathBase<Path>
定义 Path
时也没有声明明确的特化;它会触发 PathBase<Path>
的隐式实例化 ,基于您在上面提供的定义。类模板的隐式实例化实例化类定义,并且仅实例化其成员函数的声明;它不会尝试实例化函数的定义;这些仅在需要时实例化,稍后再实例化。
在您的 cpp 文件中,您明确特化了 IsSeparator
和 Separators
对于隐式实例化的 PathBase<Path>
.您要求编译器实例化 PathBase<Path>
基于您提供的通用定义,但是,当需要这些特定功能的定义时,请使用您提供的特定定义。
当类的结构和大多数成员的通用定义都很好,而您只想微调少数成员的定义时,它基本上是显式特化整个类模板的一种速记替代方法。如果您显式特化整个类模板,则必须为特化的所有成员函数提供单独的类定义和定义,这意味着不必要的复制粘贴。
您需要尽快告诉编译器这些显式特化,以免某些代码尝试使用这些定义(它需要知道它必须寻找特定定义而不是通用定义) .您可以通过声明(不一定定义)显式特化来做到这一点。
最安全的地方是紧跟在 template <class T> class PathBase
定义的右大括号之后.像这样的东西:
class Path;
template<> std::string PathBase<Path>::Separators() const;
template<> bool PathBase<Path>::IsSeparator(char c) const;
您绝对需要在头文件中执行此操作,而不是在 cpp 文件中,否则使用头文件的其他 cpp 文件将不知道显式特化,并将尝试实例化通用版本(如果需要)。这将使您的程序格式错误,不需要诊断(这也适用于您的示例)。这意味着:如果编译器足够聪明,可以诊断出问题,你应该感激不尽;如果不是,你不能提示,这仍然是你的错。
在预先声明显式特化后,定义可以稍后出现,可能在单独的 cpp 文件中;没关系,就像正常功能一样。
另请注意,如果您想在头文件中包含显式特化的定义(例如,为了简化内联),您必须声明它们 inline
,再次像正常功能一样。否则,在多个 cpp 文件中包含 header 将使程序格式错误,NDR(您通常会在链接时遇到多个定义错误)。
来自 [temp.expl.spec]/7 的强制性标准报价:
[...] When writing a specialization, be careful about its location; or to make it compile will be such a trial as to kindle its self-immolation.
是的,标准化委员会的成员也是人。
关于c++ - 声明不能解决 'explicit specialization after instantiation' 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40826618/
在围棋中,我尝试了简单的数据库连接。我需要进口大猩猩/MUX,但我不能。。我正在使用VS代码。在cd进入我的项目目录之后,我创建了main.go并运行了go get-u githorb.com/Gor
当基类中唯一的候选构造函数被标记为explicit时,派生类的实例是否可以隐式转换为其基类的实例? 我运行了这个: struct Base { Base() {} explicit Bas
我正在尝试创建一个模板类来强制执行尺寸正确性(长度除以时间得出速度,等等)。 短篇小说:“无量纲”是可能的实例之一。如果我可以允许所有实例化显式地从 double 构造,并且进一步允许“无量纲”实例化
为什么下面的代码不能编译,而当我在类 A 中删除构造函数之前的显式关键字时,它可以编译? 使用 Visual Studio 2013: enum E { e1_0, e1_1 }; template
有人能解释一下为什么我在这里遇到编译错误 - 错误 C2558:类“std::auto_ptr”:没有可用的复制构造函数或复制构造函数被声明为“显式” #include #include #inc
目前,我的 Localizable.strings 文件的文本编码设置为UTF-8。我所有其他可本地化的文件都设置为 no explicit。 我想将 UTF-8 更改为 No explicit,这怎
请引用Wikipedia:Strategy Pattern (C++) class Context { private: StrategyInterface * strateg
是否有理由为不带任何参数的构造函数使用 explicit 关键字?它有什么作用吗?我想知道,因为我刚刚遇到了这条线 explicit char_separator() 在记录 boost::char_
我经常听到人们称赞语言、框架、结构等是“明确的”。我试图理解这个逻辑。语言、框架等的目的是隐藏复杂性。如果它让您明确指定各种细节,那么它并没有隐藏太多复杂性,只是四处移动。显式有什么好处,你如何使语言
我知道有一些关于此的帖子,但大约一年了,没有回复。实际上我们使用的是 Hibernate 4.2.1.Final 而不是 PostgreSQL 8.4。我们有两个这样的实体 实体 A(顶级层次结构类)
数据“显式”传递给函数,而方法“隐式传递”给调用它的对象。 请您解释一下这两种传递数据的方式之间的区别? java 或 c# 中的示例会有所帮助。 最佳答案 Java 和 Python 语言就是说明这
R 非常棒:精简而灵活,但又强大又开放。对于小任务,如果不必在使用前声明每个变量会很方便。但是:特别是。在较大的项目中,小的拼写错误可能会搞砸一切,甚至可能没有错误消息(参见示例)! 有解决办法吗?如
我使用 python 和 selenium 编写了一个脚本,用于单击谷歌地图侧栏中列出的一些链接。单击任何项目时,每个潜在客户所附加的相关信息都会显示在右侧区域中。剧本做得很好。但是,我使用硬编码
在同一个页面同一个步骤,如果使用“wait”会得到错误信息“NoSuchElementException:消息:无法找到名称 == rw 的元素” 如果使用“switch_to_frame”将成功切换
我有以下代码部分,它给出了明确的 null 取消引用。 uint64_t *var1 = NULL; char *var2 = NULL; //Alias transfer var1 = (uint6
我的任务是迁移 C++ 类库中的错误处理概念。以前简单返回 bool(成功/失败)的方法应修改为返回一个 Result 对象,该对象传达机器可读的错误代码和人类可读的解释(以及更多在这里无关紧要的内容
我对这行代码有疑问: class S1Es3SharedState { //lock private final Lock lock = new ReentrantLock();
当我在我的代码中使用(最近发布的)Cppcheck 1.69 时 1 ,它显示了很多我没有预料到的消息。禁用 noExplicitConstructor 证明它们都属于这种类型。 但我发现我不是唯一一
这个问题与之前的 C++11 (C++03) 标准有关。 explicit 防止从一种类型到另一种类型的隐式转换。例如: struct Foo { explicit Foo(int); };
我们正在使用的外部库包含以下显式构造函数: class Chart { public: explicit Chart(Chart::Type type, Object *parent);
我是一名优秀的程序员,十分优秀!