19

用旧版本的g++(4.8.0,MinGW)编译项目我发现这段代码编译失败:

template<typename T>
void foo() = delete;

template<>
void foo<int>(){}

int main() {
    foo<int>();
    return 0;
}

如果发现基本情况已被删除,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 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

相反,g++ 4.8.4 和 5.2(在 Linux 上)不会抱怨。这是旧版本编译器中的错误还是标准中的灰色区域?


附录

clang 3.4.1 似乎也不喜欢它:

mitalia@mitalia:~/scratch$ clang++ -std=c++11 buggy_deleted_template.cpp                                                             
buggy_deleted_template.cpp:5:6: error: redefinition of 'foo'                                                                         
void foo<int>(){}
     ^
buggy_deleted_template.cpp:5:6: note: previous definition is here
buggy_deleted_template.cpp:8:5: error: no matching function for call to 'foo'
    foo<int>();
    ^~~~~~~~
buggy_deleted_template.cpp:2:6: note: candidate template ignored: substitution failure [with T = int]
void foo() = delete;
     ^
2 errors generated.
mitalia@mitalia:~/scratch$ clang++ --version
Ubuntu clang version 3.4-1ubuntu3 (tags/RELEASE_34/final) (based on LLVM 3.4)
Target: x86_64-pc-linux-gnu
Thread model: posix

(评论中的@Baum mit Augen报告说它在 3.7 中仍然不起作用)

4

1 回答 1

11

我不知道以下内容是否有启发性,但我发现了缺陷报告 941:Explicit specialization of deleted function template with status C++11 指出以下内容(Emphasis Mine)

根据 14.7.3 [temp.expl.spec] 第 1 段,只有未删除的函数模板可以显式特化。然而,对这个限制似乎没有迫切的需求,禁止使用隐式实例化的特化同时仍然允许使用显式特化的版本可能很有用。

提议的决议(2010 年 2 月):

将 14.7.3 [temp.expl.spec] 第 1 段更改如下:

以下任何一项的明确专业化:

未删除功能模板

类模板

未删除类模板的成员函数

类模板的静态数据成员

类模板的成员类

类或类模板的成员类模板

未删除类或类模板的成员函数模板

可以声明...

现在标准草案N4527的当前状态是14.7.3 Explicit specialization [temp.expl.spec]:

1 以下任何一项的明确专业化:

(1.1)——函数模板

(1.2)——类模板

(1.3)——变量模板

(1.4) — 类模板的成员函数

(1.5) — 类模板的静态数据成员

(1.6)——类模板的成员类

(1.7) — 类模板的成员枚举

(1.8)——类的成员类模板或类模板

(1.9)——类的成员函数模板或类模板

...

所以我猜:

template<typename T>
void foo() = delete;

template<>
void foo<int>(){}

int main() {
    foo<int>();
    return 0;
}

是 C++11 标准兼容代码并且应该被接受。

于 2015-10-21T11:33:42.183 回答