在编写一个供个人使用的小型模板元编程库时,我遇到了一个有趣的问题。
由于我为某些元函数重用了一些偏特化,因此我决定将它们放在一个通用模板类下,并使用标签和嵌套偏特化来提供行为差异。
问题是我得到了(对我而言)荒谬的结果。这是一个展示我正在尝试做的事情的最小示例:
#include <iostream>
#include <cxxabi.h>
#include <typeinfo>
template <typename T>
const char * type_name()
{
return abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, nullptr);
}
template <typename... Args>
struct vargs {};
namespace details
{
template <typename K>
struct outer
{
template <typename Arg>
struct inner
{
using result = Arg;
};
};
}
struct tag {};
namespace details
{
template <>
template <typename Arg, typename... Args>
struct outer<tag>::inner<vargs<Arg, Args...>>
{
using result = typename outer<tag>::inner<Arg>::result;
};
}
template <typename T>
using test_t = typename details::outer<tag>::inner<T>::result;
int main()
{
using t = test_t<vargs<char, int>>;
std::cout << type_name<t>() << '\n';
return 0;
}
我收到 vargs<char, int>作为使用 5.1.0 版本的 gcc 和 tag 时的输出使用 3.6.0 版本的 clang 时。我的意图是打印上面的代码 char所以我对这些结果感到很困惑。
上面的代码是合法的还是表现出未定义的行为? 如果它是合法的,那么根据标准的预期行为是什么?
最佳答案
您的代码是正确的;类外隐式实例化类模板成员类模板部分特化旨在被标准允许,只要它们定义得足够早。
首先,让我们尝试一个最小的示例 - 顺便注意这里没有任何东西需要 C++11:
template<class T> struct A {
template<class T2> struct B { };
};
// implicitly instantiated class template member class template partial specialization
template<> template<class T2>
struct A<short>::B<T2*> { };
A<short>::B<int*> absip; // uses partial specialization?
正如其他地方所指出的,MSVC 和 ICC 使用部分特化,正如预期的那样; clang 选择了部分特化,但弄乱了它的类型参数,别名 T2至short而不是 int ;而 gcc 完全忽略了部分特化。
简单地说,允许其他形式的类模板成员类模板定义的语言都不排除类外隐式实例化的类模板成员类模板部分特化。在 [temp.mem] 中,我们有:
1 - A template can be declared within a class or class template; such a template is called a member template. A member template can be defined within or outside its class definition or class template definition. [...]
类模板部分特化是模板声明 ([temp.class.spec]/1)。在同一段中,还有一个类外非特化类模板成员类模板部分特化的例子([temp.class.spec]/5):
template<class T> struct A {
struct C {
template<class T2> struct B { };
};
};
// partial specialization of A<T>::C::B<T2>
template<class T> template<class T2>
struct A<T>::C::B<T2*> { };
A<short>::C::B<int*> absip; // uses partial specialization
这里没有任何东西表明封闭范围不能是封闭类模板的隐式特化。
类似的还有类内类模板成员类模板部分特化和类外隐式实例化类模板成员类模板全特化的例子([temp.class.spec.mfunc]>2):
template<class T> struct A {
template<class T2> struct B {}; // #1
template<class T2> struct B<T2*> {}; // #2
};
template<> template<class T2> struct A<short>::B {}; // #3
A<char>::B<int*> abcip; // uses #2
A<short>::B<int*> absip; // uses #3
A<char>::B<int> abci; // uses #1
(clang (截至 3.7.0-svn235195) 得到第二个示例错误;它为 absip 选择 #2 而不是 #3。)
虽然这里没有明确提到类外隐式实例化类模板成员类模板部分特化,但也不排除它;它不在这里的原因是它与所提出的特定点无关,即哪个主模板或部分模板特化被认为是特定特化的。
根据[temp.class.spec]:
6 - [...] when the primary template name is used, any previously-declared partial specializations of the primary template are also considered.
在上面的最小示例中,A<short>::B<T2*>是主模板的部分特化 A<short>::B所以应该考虑。
在其他讨论中,我们看到提到隐式实例化(封闭类模板)可能导致发生主模板特化定义的隐式实例化,从而导致格式错误的程序 NDR,即 UB; [templ.expl.spec]:
6 - If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required. [...]
但是,这里的类模板成员类模板在实例化之前是没有用到的。
在 DR1755 (active) ,给出的例子是:
template<typename A> struct X { template<typename B> struct Y; };
template struct X<int>;
template<typename A> template<typename B> struct X<A>::Y<B*> { int n; };
int k = X<int>::Y<int*>().n;
仅从实例化封闭类的第二行存在的角度来看,这被认为是有问题的。提交者(Richard Smith)或 CWG 没有建议即使没有第二行也可能无效。
在 n4090 ,给出的例子是:
template<class T> struct A {
template<class U> struct B {int i; }; // #0
template<> struct B<float**> {int i2; }; // #1
// ...
};
// ...
template<> template<class U> // #6
struct A<char>::B<U*>{ int m; };
// ...
int a2 = A<char>::B<float**>{}.m; // Use #6 Not #1
这里提出的问题是类内类模板成员类模板完全特化和类外类模板实例化成员类模板部分特化之间的优先级;没有建议 #6根本不会考虑。
关于c++ - gcc 和 clang 上奇怪的嵌套类部分特化结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31393530/
我得到了一个包含嵌套链接的表单。编辑时链接字段为空的问题。这是我的表格:Editingkategori{:action=>'update',:id=>@konkurrancer.id})do|f|%>'Trackingurl',:style=>'width:500;'%>'Editkonkurrence'%>|我的konkurrencer模型:has_one:link我的链接模型:classLink我的konkurrancer编辑操作:defedit@konkurrancer=Konkurrancer.find(params[:id])@konkurrancer.link_attrib
这道题是thisquestion的逆题.给定一个散列,每个键都有一个数组,例如{[:a,:b,:c]=>1,[:a,:b,:d]=>2,[:a,:e]=>3,[:f]=>4,}将其转换为嵌套哈希的最佳方法是什么{:a=>{:b=>{:c=>1,:d=>2},:e=>3,},:f=>4,} 最佳答案 这是一个迭代的解决方案,递归的解决方案留给读者作为练习:defconvert(h={})ret={}h.eachdo|k,v|node=retk[0..-2].each{|x|node[x]||={};node=node[x]}node[
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我正在尝试在我的centos服务器上安装therubyracer,但遇到了麻烦。$geminstalltherubyracerBuildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingtherubyracer:ERROR:Failedtobuildgemnativeextension./usr/local/rvm/rubies/ruby-1.9.3-p125/bin/rubyextconf.rbcheckingformain()in-lpthread...yescheckingforv8.h...no***e
下面例子中的Nested和Child有什么区别?是否只是同一事物的不同语法?classParentclassNested...endendclassChild 最佳答案 不,它们是不同的。嵌套:Computer之外的“Processor”类只能作为Computer::Processor访问。嵌套为内部类(namespace)提供上下文。对于ruby解释器Computer和Computer::Processor只是两个独立的类。classComputerclassProcessor#Tocreateanobjectforthisc
我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的
我有一个名为posts的模型,它有很多附件。附件模型使用回形针。我制作了一个用于创建附件的独立模型,效果很好,这是此处说明的View(https://github.com/thoughtbot/paperclip):@attachment,:html=>{:multipart=>true}do|form|%>posts中的嵌套表单如下所示:prohibitedthispostfrombeingsaved:@attachment,:html=>{:multipart=>true}do|at_form|%>附件记录已创建,但它是空的。文件未上传。同时,帖子已成功创建...有什么想法吗?
我真的为这个而疯狂。我一直在搜索答案并尝试我找到的所有内容,包括相关问题和stackoverflow上的答案,但仍然无法正常工作。我正在使用嵌套资源,但无法使表单正常工作。我总是遇到错误,例如没有路线匹配[PUT]"/galleries/1/photos"表格在这里:/galleries/1/photos/1/edit路线.rbresources:galleriesdoresources:photosendresources:galleriesresources:photos照片Controller.rbdefnew@gallery=Gallery.find(params[:galle
导读语言模型给我们的生产生活带来了极大便利,但同时不少人也利用他们从事作弊工作。如何规避这些难辨真伪的文字所产生的负面影响也成为一大难题。在3月9日智源Live第33期活动「DetectGPT:判断文本是否为机器生成的工具」中,主讲人Eric为我们讲解了DetectGPT工作背后的思路——一种基于概率曲率检测的用于检测模型生成文本的工具,它可以帮助我们更好地分辨文章的来源和可信度,对保护信息真实、防止欺诈等方面具有重要意义。本次报告主要围绕其功能,实现和效果等展开。(文末点击“阅读原文”,查看活动回放。)Ericmitchell斯坦福大学计算机系四年级博士生,由ChelseaFinn和Chri
如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是: