【问题标题】:Why does this code compile with g++ but not MSVC++?为什么这段代码用 g++ 而不是 MSVC++ 编译?
【发布时间】:2026-02-09 02:15:01
【问题描述】:

我正在尝试编译一些开源代码 (https://github.com/BieremaBoyzProgramming/bbpPairings),我可以使用 g++ (v6.3.0) 在 linux 上编译这些代码,但无法在 Visual Studio (VS Community 2019) 中编译/16.1.5),有点晦涩(对我来说,但我的 C++ 确实很弱)错误:“错误 C2143:语法错误:缺少';'在'

源代码中的违规代码是here,但从代码中提取的一个最小示例是:

#include <iostream>
#include <random>

class Configuration {};

class MatchesConfiguration {
public:
    template <class RandomEngine>
    MatchesConfiguration(
        Configuration&&,
        RandomEngine&);
};

template <class RandomEngine>
MatchesConfiguration::MatchesConfiguration(
    Configuration&& configuration,
    RandomEngine& randomEngine) {}

template
MatchesConfiguration::MatchesConfiguration<std::minstd_rand>( // <--- SYNTAX ERROR HERE
    Configuration&&,
    std::minstd_rand&);

int main()
{
    std::cout << "Hello World!\n"; 
}

我查看了MSDN description of the error code,但我对 C++ 和模板的掌握太薄弱,无法弄清楚出了什么问题。项目 README 说 C++14 是预期的(对于 FS 的东西有一些可选的 C++17 东西,我认为在这里不重要),但据我所知,feature compatibility chart all of C+ VS 2019 应该支持 +14。

【问题讨论】:

  • 我无法编译on Coliru,它使用g++ 8.2.0。
  • 我对较新版本的 MSVC++ 没有那么丰富的经验,但这听起来像是应用程序中的兼容性设置。我认为,默认情况下,g++ v6.3.0 可能会编译期望 C++ 语言的旧版本。 g++ 6.5 是在去年 10 月根据gcc.gnu.org 发布的,所以我预计 6.3.0 会明显更早。您可能需要在 MSVC++ 中设置兼容性以符合旧版本的语言。
  • 你想要这个godbolt.org/z/hpj4dK吗?
  • 是否允许这种孤独的template 事情?不应该是template&lt;&gt;吗?
  • @EtiennedeMartel No. template&lt;&gt; 用于显式特化,但此代码正在执行显式实例化

标签: c++ visual-c++ c++14


【解决方案1】:

当您提供constructorexplicit instantiation definition(根据标准实际上没有名称)时,您应该通过提供您想要实例化的签名来做到这一点,如下所示:

template
MatchesConfiguration::MatchesConfiguration(  // no <std::minstd_rand> here
    Configuration&&,
    std::minstd_rand&);

[temp.arg.explicit#2]

当引用一个模板时,不应指定模板参数 构造函数模板的特化


旧笔记中的琐事(从 2006 年开始):
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#581

"模板化的构造函数可以显式实例化或特化吗?"

不可能指定构造函数的模板参数 构造函数调用(因为构造函数没有名称但 使用构造函数的类名调用)

[...]

据观察,实际上从来没有必要在构造函数声明中显式指定模板参数,因为根据定义,参数都是可推导的,因此可以省略。

请注意,普通函数模板可以具有不可推导的模板参数,必须为实例化或特化显式提供。

感谢 Davis Herring 和 M.M 的指导

【讨论】:

  • 你应该说为什么这里禁止显式参数列表(与普通成员函数不同)。
  • @DavisHerring 我已经尝试过了。如果这完全具有误导性,我不介意有人只是恢复我的编辑。
  • 您链接到 cppreference 页面以进行类模板实例化,但这实际上是 function template,构造函数。第二个编号列表中的用法(2)
  • @DavisHerring CWG 的注释是各种参考......没有人明确(急忙)提到问题是成员函数模板显式实例化的语法不能用于构造函数(因为构造函数“名称”实际上不是函数名称,从语法上讲,构造函数就像一个未命名的函数,可以在某些上下文中通过重复函数名称来表示;但在此上下文中被忽略了)。 CWG 的问题是询问他们是否应该修改标准语法来解决这个问题,但他们认为没有必要
  • @TedLyngmo:看起来不错。我只是要注意,普通函数模板可以具有不可推导的模板参数,必须为实例化或特化显式提供。