我想和你们分享一个我偶然发现的奇怪的例子,这让我思考了两天。
要让这个例子正常工作,您需要:
getAsString())Value<bool>::getAsString())覆盖虚函数你从一个模板类开始,它实际上继承了一个公共(public)接口(interface)——即一组虚函数。稍后,我们将特化其中一个虚函数。内联可能会导致我们的特化被忽视。
// test1.cpp and test2.cpp
#include <string>
class ValueInterface_common
{
public:
virtual ~ValueInterface_common() {}
virtual const std::string getAsString() const=0;
};
template <class T>
class Value :
virtual public ValueInterface_common
{
public:
virtual ~Value() {}
const std::string getAsString() const;
};
template <class T>
inline const std::string Value<T>::getAsString() const
{
return std::string("other type");
}
接下来我们要继承这个Value Parameter 中的类和接口(interface)本身也需要模板化的类:
// test1.cpp
template <class T>
class Parameter :
virtual public Value<T>,
virtual public ValueInterface_common
{
public:
virtual ~Parameter() {}
const std::string getAsString() const;
};
template<typename T>
inline const std::string Parameter<T>::getAsString() const
{
return Value<T>::getAsString();
}
现在,不要(!)给出 Value 特化的前向声明对于类型等于 bool ...
// NOT in: test1.cpp
template <>
const std::string Value<bool>::getAsString() const;
而是像这样简单地给出它的定义......
// test2.cpp
template <>
const std::string Value<bool>::getAsString() const
{
return std::string("bool");
}
.. 但在另一个模块中(这很重要)!
最后,我们有一个 main()函数来测试正在发生的事情:
// test1.cpp
#include <iostream>
int main(int argc, char **argv)
{
ValueInterface_common *paraminterface = new Parameter<bool>();
Parameter<int> paramint;
Value<int> valint;
Value<bool> valbool;
Parameter<bool> parambool;
std::cout << "paramint is " << paramint.getAsString() << std::endl;
std::cout << "parambool is " << parambool.getAsString() << std::endl;
std::cout << "valint is " << valint.getAsString() << std::endl;
std::cout << "valbool is " << valbool.getAsString() << std::endl;
std::cout << "parambool as PI is " << paraminterface->getAsString() << std::endl;
delete paraminterface;
return 0;
}
如果您按如下方式编译代码(我将其放入名为 test1.cpp 和 test2.cpp 的两个模块中,后者仅包含特化和必要的声明):
g++ -O3 -g test1.cpp test2.cpp -o test && ./test
输出是
paramint is other type
parambool is other type
valint is other type
valbool is bool
parambool as PI is other type
如果使用 -O0 编译或者只是 -fno-inline - 或者如果您确实给出了特化的前向声明 - 结果变为:
paramint is other type
parambool is bool
valint is other type
valbool is bool
parambool as PI is bool
很有趣,不是吗?
到目前为止,我的解释是:内联在第一个模块 (test.cpp) 中起作用。所需的模板函数被实例化,但一些最终被内联在对 Parameter<bool>::getAsString() 的调用中。 .另一方面,对于 valbool这没有用,但模板被实例化并用作函数。链接器然后找到实例化的模板函数和第二个模块中给出的专用函数,并决定使用后者。
你怎么看?
Parameter<bool>::getAsString()但不适用于 Value<bool>::getAsString()虽然两者都重写了一个虚函数?最佳答案
我推测您遇到了 ODR 问题,因此猜测为什么某些编译器优化的行为与其他编译器设置不同是没有意义的。
本质上,单一定义规则规定同一实体应 在整个应用程序中具有完全相同的定义,否则 效果未定义。
根本问题是,看不到类模板成员函数的专用版本的代码可能仍然可以编译、链接,有时甚至可以运行。这是因为在没有显式特化(前向声明)的情况下,非特化版本开始出现,可能会实现也适用于您的特化类型的通用功能。
因此,如果您幸运的话,您会收到有关缺少声明/定义的编译器错误,但如果您真的不走运,您会得到“工作”代码,但它并不是您想要的。
修复:始终包含(转发)所有模板特化的声明。最好将它们放在一个 header 中,并包含所有调用您的类的客户端的 header 以获取任何可能的模板参数。
// my_template.hpp
#include "my_template_fwd.hpp"
#include "my_template_primary.hpp"
#include "my_template_spec_some_type.hpp"
// my_template_fwd.hpp
template<typename> class my_template; // forward declaration of the primary template
// my_template_primary.hpp
#include "my_template_fwd.hpp"
template<typename T> class my_template { /* full definition */ };
// my_template_spec_some_type.hpp
#include "my_template_fwd.hpp"
template<> class my_template<some_type> { /* full definition */ };
// some_client_module.hpp
#include "my_template.hpp" // no ODR possible, compiler will always see unique definition
显然,您可以通过为模板特化创建子目录并相应地更改包含路径来重新组织命名。
关于c++ - 内联导致覆盖虚函数的模板类的专门成员函数被忽略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14264855/
我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我正在使用puppet为ruby程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这
我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re
我在pry中定义了一个函数:to_s,但我无法调用它。这个方法去哪里了,怎么调用?pry(main)>defto_spry(main)*'hello'pry(main)*endpry(main)>to_s=>"main"我的ruby版本是2.1.2看了一些答案和搜索后,我认为我得到了正确的答案:这个方法用在什么地方?在irb或pry中定义方法时,会转到Object.instance_methods[1]pry(main)>defto_s[1]pry(main)*'hello'[1]pry(main)*end=>:to_s[2]pry(main)>defhello[2]pry(main)
我正在尝试用ruby中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了
我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr
对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs
我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin
在Ruby类中,我重写了三个方法,并且在每个方法中,我基本上做同样的事情:classExampleClassdefconfirmation_required?is_allowed&&superenddefpostpone_email_change?is_allowed&&superenddefreconfirmation_required?is_allowed&&superendend有更简洁的语法吗?如何缩短代码? 最佳答案 如何使用别名?classExampleClassdefconfirmation_required?is_a