我有一个带有模板化成员函数的模板化类
template<class T>
class A {
public:
template<class CT>
CT function();
};
Run Code Online (Sandbox Code Playgroud)
现在我想以两种方式专门化模板化成员函数.首先是与类相同的类型:
template<class T>
template<> // Line gcc gives an error for, see below
T A<T>::function<T>() {
return (T)0.0;
}
Run Code Online (Sandbox Code Playgroud)
类型bool的第二个:
template<class T>
template<>
bool A<T>::function<bool>() {
return false;
}
Run Code Online (Sandbox Code Playgroud)
这是我试图测试它的方式:
int main() {
A<double> a;
bool b = a.function<bool>();
double d = a.function<double>();
}
Run Code Online (Sandbox Code Playgroud)
现在gcc给了我上面标记的行:
error: invalid explicit specialization before ‘>’ token
error: enclosing class templates are not explicitly specialize
Run Code Online (Sandbox Code Playgroud)
所以gcc告诉我,如果我想专攻功能,我必须专攻A,对吗?我不想这样做,我希望外类的类型是开放的...
最后的答案是:这是不可能的?或者有办法吗?
我正在努力了解它的用处static_assert
,我想知道它是否可以帮助我执行设计,如果是,那么如何.
我有一个通用的模板类,它在另一个模板类中隐藏它自己的实现,这个类是基于模板类型的大小而部分专用的.以下是此设计的简要概述:
template <class T, size_t S = sizeof(T)>
struct Helper;
template <class T>
struct Helper<T, sizeof(long)>
{
static T bar();
};
// ... other specializations ...
template <class T>
class Foo
{
public:
T bar()
{
return Helper<T>::bar();
}
};
Run Code Online (Sandbox Code Playgroud)
美孚如果尺寸仅支持T
由一个专业化的支持助手.例如,Foo<long>
并且Foo<unsigned long>
都受支持.但是,假设用户尝试构造一个Foo<bool>
.通常,这会产生错误,因为没有定义Helper for的特化bool
,这是预期的行为.
static_assert
在此设计中是否有任何方法可以为此界面的用户提供更多有用的错误?
此外,我还想限制用户使用特定类型,即使大小可能是正确的.例如,Foo<float>
不应该被允许.现在,我知道强制执行此操作的唯一方法是通过文档中的大胆注释.:)
我刚刚专门std::hash
针对用户定义的类型使用:
template<>
struct hash<...> {...};
Run Code Online (Sandbox Code Playgroud)
当VC10向我发出警告时:
警告C4099:'std :: hash <_Kty>':使用'struct'时首先看到使用'class'看到的类型名称
我发现它的标准库声明std::hash
为class
,而标准(或我最新的自由草案)声明为struct
.
好吧,当然我知道结构与类没有任何不同(除了不同的默认访问和继承类型).但我的问题是:
struct
s class
(当然,只要成员所需的访问类型保持一致)?以下位代码无法在gcc 4.5.3上编译
struct Frobnigator
{
template<typename T>
void foo();
template<typename T>
void bar();
};
template<typename T>
void Frobnigator::bar()
{
}
template<typename T>
void Frobnigator::foo()
{
bar<T>();
}
template<> // error
void Frobnigator::foo<bool>()
{
bar<bool>();
}
template<>
void Frobnigator::bar<bool>()
{
}
int main()
{
}
Run Code Online (Sandbox Code Playgroud)
错误讯息:specialization of ‘void Frobnigator::bar() [with T = bool]’ after instantiation
.我终于解决了这个问题,因为Frobnigator::bar<bool>()
之前出现了专门化Frobnigator::foo<bool>()
.显然,方法看起来很重要.
那么为什么以上是上面代码的lite版本,其中bar
泛型版本之后出现的特化,有效吗?
struct Frobnigator
{
template<typename T>
void foo();
};
template<typename T>
void Frobnigator::bar()
{
}
template<>
void Frobnigator::bar<bool>() …
Run Code Online (Sandbox Code Playgroud) 有人可以解释为什么一次使用方法c(T*)
和下一次d<>(int*)
?方法c
和d
我似乎完全相同,我无法弄清楚为什么不是同一类型的方法调用.
#include <iostream>
using namespace std;
template<typename T>
void c(T){ cout <<"(T)" << endl; }
template<>
void c<>(int*){ cout <<"(int*)" << endl; }
template<typename T>
void c(T*){ cout <<"(T*)" << endl; }
template<typename T>
void d(T){ cout <<"(T)" << endl; }
template<typename T>
void d(T*){ cout <<"(T*)" << endl; }
template<>
void d<>(int*){ cout <<"(int*)" << endl; }
int main(){
int i;
c(&i);
d(&i);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
(T*)
(int*)
Run Code Online (Sandbox Code Playgroud) 一类:
template<typename C, typename T>
class A
{
template <typename U>
class Nested{};
Nested<T> n;
};
Run Code Online (Sandbox Code Playgroud)
我想专攻Nested
.这是我尝试过的:
template<typename C, typename T>
class A
{
template <typename U>
class Nested{};
template <>
class Nested<int>{}; // by my logic this should work by I have a compilation error "explicit specialization in non-namespace scope 'class A<C, T>'"
Nested<T> n;
};
Run Code Online (Sandbox Code Playgroud)
我的下一次尝试:
template<typename C, typename T>
class A
{
template <typename U>
class Nested{};
Nested<T> n;
};
template<>
A<>::Nested<int>{}; // What is …
Run Code Online (Sandbox Code Playgroud) 使用旧版本的g ++(4.8.0,MinGW)编译项目我发现此代码无法编译:
template<typename T>
void foo() = delete;
template<>
void foo<int>(){}
int main() {
foo<int>();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
似乎g ++甚至没有尝试寻找显式特化,如果它看到基本情况被删除.
mitalia@mitalia:~/scratch$ /opt/mingw32-dw2/bin/i686-w64-mingw32-g++ -std=c++11 buggy_deleted_template.cpp
buggy_deleted_template.cpp: In function 'int main()':
buggy_deleted_template.cpp:8:14: error: use of deleted function 'void foo() [with T = int]'
foo<int>();
^
buggy_deleted_template.cpp:5:6: error: declared here
void foo<int>(){}
^
mitalia@mitalia:~/scratch$ /opt/mingw32-dw2/bin/i686-w64-mingw32-g++ --version
i686-w64-mingw32-g++ (rubenvb-4.8.0) 4.8.0
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for …
Run Code Online (Sandbox Code Playgroud) c++ templates template-specialization deleted-functions c++11
考虑以下程序:
template<template<typename ...> class>
struct foo {};
template<template<typename> class C>
struct foo<C> {};
int main() {}
Run Code Online (Sandbox Code Playgroud)
Clang拒绝了它的错误:
类模板部分特化不会专门化任何模板参数
即使在最新的clang 7.0 HEAD中,请参见此处的演示.但是,gcc接受了它.
请参阅[temp.class.spec],其中陈述了部分特化的规则,我找不到任何禁止该模板的部分特化的东西.特别是,专业化确实更专业,错误消息看起来不正确.
编辑:
但是,gcc的行为也是异常的,请考虑以下程序:
#include <iostream>
template<template<typename ...> class>
struct foo { void show() { std::cout << "Primary.\n"; } };
template<template<typename> class C>
struct foo<C> { void show() { std::cout << "Specialized.\n"; } };
template<class...> struct bar {};
int main() {
foo<bar> f;
f.show();
}
Run Code Online (Sandbox Code Playgroud)
事实证明,gcc在这种情况下使用专用版本,请参见此处.
现在我想问:
是标准允许的这种局部专业化吗?
哪个编译器是正确的?(一个/全部/没有?)
上下文:令我们惊讶的是,启用 C++20 模式和两阶段合规性的 MSVC 接受以下代码:
\ntemplate<class T>\nclass X\n{\n friend int foo<X>(X x);\n\n int a = 10;\n};\n\ntemplate <class T>\nint foo(T t)\n{\n return t.a;\n}\n\nint main()\n{\n return foo(X<float>{});\n}\n
Run Code Online (Sandbox Code Playgroud)\n这会编译/链接并10
在 MSVC 和 gcc 中返回(但会发出 clang 声): https: //godbolt.org/z/98cd7v7a6。
那些了解两阶段查找的人会发现这看起来非常疯狂 - 我们可以在声明相应的模板之前以某种方式与模板专门化成为朋友。看起来和听起来都很不对劲。事实上,对于早期的 C++ 版本,所有编译器都会立即拒绝它: https: //godbolt.org/z/M1733EPd5
\n但 C++20 中的以下措辞似乎为此铺平了道路(或者至少使其从一开始就不是完全错误的):https://timsong-cpp.github.io/cppwp/n4861/temp .names#2.sentence-4(强调我的)
\n\n\n如果名称是一个 unqualified-id 后跟一个名称,则该名称也被视为引用模板,并且
\n<
名称查找要么找到一个或多个函数,要么什么也没找到。
现在,这导致了一大堆……好吧,荒谬的极端情况。请注意,在声明之外,friend
您必须以 开始模板专门化template<>
,但声明中的情况并非如此friend
。可以预见的是,编译器甚至无法就现在合法和不合法的内容达成一致:
交朋友... | 神箭 … |
---|
我有代码:
#include <cstdio>
template<template<typename...> class>
struct Foo
{
enum { n = 77 };
};
template<template<typename, typename...> class C>
struct Foo<C>
{
enum { n = 99 };
};
template<typename...> struct A { };
template<typename, typename...> struct B { };
int main(int, char**)
{
printf("%d\n", Foo<A>::n);
printf("%d\n", Foo<B>::n);
}
Run Code Online (Sandbox Code Playgroud)
这个想法是它template<typename, typename...> class
的一个子集template<typename...> class
,因此有可能专注于它.但它非常深奥,所以也许不是.我们来试试吧.
GCC 4.7说:
$ g++ -std=c++11 test157.cpp
Run Code Online (Sandbox Code Playgroud)
它汇编了!
运行它:
$ ./a.out
77
99
Run Code Online (Sandbox Code Playgroud)
有用!
Clang 3.1说:
$ clang++ -std=c++11 test157.cpp
test157.cpp:10:8: error: class template …
Run Code Online (Sandbox Code Playgroud) c++ templates template-specialization variadic-templates c++11