C++20 中不允许结构模板重载的设计原因是什么?

NoS*_*tAl 4 c++ c++-concepts c++20

在回答我之前的问题时,我了解到 C++ 20 概念不允许重载结构模板参数,例如这不起作用:

#include <concepts>

template <std::integral>
struct S{

};
template <std::floating_point>
struct S{
};
Run Code Online (Sandbox Code Playgroud)

对于好奇的 clang 错误是类似的,但这并不重要,因为我知道 C++ 标准不允许此代码工作:

模板重新声明中的类型约束不同

我发现这种编写模板的非工作方式非常自然,所以我想知道是否曾经考虑过这一点,如果是的话,为什么它在标准化过程中被拒绝?

PS 这似乎在 C++20 中有效,但我发现它丑陋得多

#include <concepts>
#include <iostream>

template <typename T>
requires std::integral<T> || std::floating_point<T>
struct S{

};
template <std::integral T>
struct S<T>{
    static constexpr char msg[] = "i";

};
template <std::floating_point T>
struct S<T>{
    static constexpr char msg[] = "fp";
};

int main() {
    std::cout <<  S<char>::msg << std::endl;
    std::cout <<  S<double>::msg << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

Dav*_*ing 10

C++ 从来没有类或类模板的重载。类当然没有可以选择重载的参数,但也不能编写

\n
template<class> struct A {};\ntemplate<int> struct A {};\n
Run Code Online (Sandbox Code Playgroud)\n

即使对于每个template-id来说,很明显哪个属于(A<int> vs. A<1>)。这种限制有几个原因:

\n
    \n
  1. 编写使用在实例化时选择的上述重载之一的泛型A<\xe2\x80\xa6>代码是不可能的:对于每个,参数是类型还是值都是固定的,即使它是依赖的。(当然,如果重载是template<int&>和,则 \xe2\x80\x99 就不会成立。)template<float&>
  2. \n
  3. 有时会在没有任何模板参数的情况下提到模板,并且没有语法来选择两者都可能适用的模板。其中一种上下文是模板模板参数(可能是通用类型template<class...> class);另一个是 CTAD。
  4. \n
  5. 需要一些类似ADL的机制来支持在使用模板的通用代码之后为应用程序类型重载类模板的情况。
  6. \n
  7. 通常不可能确定部分特化属于哪个重载。
  8. \n
\n

C++20 的行为只是这个模型的延续;添加通用的\xe2\x80\x99并不难

\n
template<class> struct S;  // undefined\n
Run Code Online (Sandbox Code Playgroud)\n

作为声明为的部分专业化的保护伞

\n
template<std::integral I>\nstruct S<I> {};\ntemplate<std::floating_point F>\nstruct S<F> {};\n
Run Code Online (Sandbox Code Playgroud)\n


Seb*_*ian 6

模板参数推导不适用于类模板的显式特化(与函数模板相比)。这与概念本身无关。您将需要template<>关键字和<T>参数。

我不知道也找不到任何标准提案来进一步缩短这个时间。

在下面的代码中,尤其是 的主要定义S比问题中的工作版本短得多。

#include <concepts>

template <typename T>
concept Number = std::integral<T> || std::floating_point<T>;


template <Number T>
struct S;

template <std::integral T>
struct S<T>{
};

template <std::floating_point T>
struct S<T>{
};
Run Code Online (Sandbox Code Playgroud)

上面的代码可以编译并运行。

通过使用Number错误消息的第一行进行实例化,S例如std::string:

error: template constraint failure for 'template<class T> requires Number<T> struct S'

这很容易理解并且切中要害(在下面几行中有关于std::string不成为 的更多详细信息integral || floating_point)。因此,可以为错误实例化构建错误消息级别(例如,您可以定义自己的integral概念,列出允许的整数类型)。