【问题标题】:why don't the template parameters participate to the class definition/redefinition为什么模板参数不参与类定义/重新定义
【发布时间】:2020-11-18 16:22:48
【问题描述】:

为什么禁止以下代码:

template <std::size_t N>
struct A
{

};

template <class T>
struct A// error: different template parameter => redeclaration
{

};

知道我们可以冗长地表达相同的想法:

template <class T>
concept C_TypePack = T::is_type_pack_concept;

template <class... Types>
struct TypePack {static constexpr bool is_type_pack_concept = true;};

template <class T>
concept C_NonTypePack = T::is_non_type_pack_concept;

template <auto... NonTypes>
struct NonTypePack {static constexpr bool is_non_type_pack_concept = true;};

template <class T>
concept C_TemplatePack = T::is_template_pack_concept;

template <C_TypePack TTypePack, C_NonTypePack TNonTypePack>
struct TemplatePack {static constexpr bool is_template_pack_concept = true;};

template <C_TemplatePack TP>
struct A;

template <std::size_t N>
struct A<TemplatePack<TypePack<>, NonTypePack<N>>>
{

};

template <class T>
struct A<TemplatePack<TypePack<T>, NonTypePack<>>>
{

};

我的问题是:为什么不允许这种代码:

template <any>
struct A;

template <std::size_t N>
struct A<N>
{

};

template <class T>
struct A<T>
{

};

我不关心“它是写在法律上”的方面。我只想从编译器的角度看看歧义在哪里。以此类推,模板函数就好了。

编辑:感谢 n 的评论。 'pronouns' m.,这是使用 std::array 作为非类型的解决方法(元组也可以):

#include <array>

// type spe

template <auto Val>
struct A;

template <auto Size>
requires (std::is_same_v<decltype(Size), std::size_t>)
struct A<Size>
{

};

template <auto SizePack>
requires (std::is_same_v<typename decltype(SizePack)::value_type, std::size_t>)
struct A<SizePack>
{

};

// var spe

struct Foo
{
    template <auto Val>
    static consteval auto initBar()
    {
        if constexpr ( std::is_same_v<decltype(Val), std::size_t> )
            return 5.;
        else if constexpr ( requires{std::is_same_v<typename decltype(Val)::value_type, std::size_t>;} )
            return -5;
        else
            return -1;
    }

    template <auto Val>
    static constexpr auto bar = initBar<Val>();
};

int main()
{
    A<std::size_t(42)> a0;
    A<std::array<std::size_t, 1>{42}> a1;
    A<std::array<std::size_t, 2>{42, 43}> a2;

    Foo::bar<std::size_t(42)>;
    Foo::bar<std::array<std::size_t, 1>{42}>;
    Foo::bar<std::array<std::size_t, 2>{42, 43}>;

    return 0;
}

问题还是一样。

【问题讨论】:

  • 我的 2c:通用类型/非类型参数对于专业化很有用,但从根本上说,模板参数是代码中某些内容的占位符。您可以在哪里同时替换有效代码中的类型值和非类型值(不包括 sizeof 和 typeid)?
  • @parktomatomi:感谢 cmets。我正在设计一个多维数组,并且我有几个开始函数以 size_t(子维度 iter)或一组 size_t(自定义 iter)作为模板。可以将它们称为 begin 并考虑相同的功能,但返回的迭代器是类型别名,不能以不同的定义称为 Iterator。
  • “以此类推,模板函数就好了。”:函数模板,以及一般的函数,重载。类声明不会重载。
  • 指定什么并不重要。为什么你需要一个类型呢?您的类型包含哪些值无法提供的内容?值可以是std::tuplestd::array 类型。

标签: c++ templates language-lawyer


【解决方案1】:

模板函数的专门化和模板类型的专门化是很不一样的。

函数参与重载决议。重载解决方案是 C++ 标准中一个极其复杂且会导致错误的部分。它“像魔术一样工作”,因为它已经完成了很多工作来让它发挥作用,而且当它与模板代码交互时,它的行为方式仍然让大多数人感到惊讶。

模板函数没有部分特化,只有完全特化;专业化只会改变使用的身体,它永远不会改变选择的身体。有两种不同的方式来改变使用的实现交互将是疯狂的。

另一方面,模板类型使用不同的方式进行选择。在这里,使用了部分和完全特化,而不是重载。

专业化是一种子类型化。主模板确定传递的参数是什么,而特化则没有。特化只是与主模板的参数匹配

您的更改将引入一组新的不同主要专业。选择你专注于哪个模板的规则必须改变并变得更加复杂,并且为程序员确定你专注于哪个模板也将更加困难。

template<class T>
struct A;
template<int x>
struct A;

template<class T, class U>
struct A< T::template apply<U> > {};

快,我刚刚专门研究了哪个模板,A&lt;int&gt;A&lt;class&gt;?现在,我现在,但是有多少人会对此感到惊讶?很多。

...

第二个问题与之前的检查有关。

template <any>
struct A;

现在,当有人执行 A&lt;T::template apply&lt;U&gt;&gt; 时,您无法检查您是否搞砸了 types-vs-values,直到该过程的后期。

还有什么

template<any x>
struct A: B<x> {};

现在我们必须在x 是一个类型、一个值和一个模板的假设下解析A&lt;x&gt; 的主体。如果其中只有 1 个或 2 个或 0 个对给定语句有效,这是否是错误?

怎么样

template<any x>
struct A {
  int y = x<3-x::green>;
};

如果 x 是一个类型,x::green 是有意义的,但现在 x&lt;?&gt; 只有在 x 是一个模板时才有意义。你做 3 遍,每个假设一个?

模板解析已经很慢、成本高且复杂。让它变得更复杂真的很难卖。

【讨论】:

  • 哇,非常感谢您的回答!你有一点考虑到模板专业化不能为了类型的乐趣而改变而不改变函数(正交性)。查看答案的结尾,我不允许这样的功能表现得像类型/非类型模板参数。如果我理解正确,重点是“不同的主要专业”。当您说它会很复杂且容易出错时,我相信您,但是让我们在几年后讨论它xd。再次感谢这些令人信服的论点。
  • 其实我认为如果constexpr/concepts/requires约束肯定应该涉及到类型重载来彻底去除模板特化。使用 gcc 8.1 和 -fconcepts,我能够用约束消除专业化的歧义,但现在使用 gcc 10 (c++20),我必须至少专门化一种类型(非类型或约束不再参与),所以我系统地添加一个枚举作为 integer_constant,从前面的模板参数推导出来。只是说概念是函数重载期间的一切,而不是类型。
猜你喜欢
  • 1970-01-01
  • 2015-10-08
  • 2012-12-21
  • 2012-09-21
  • 2014-08-18
  • 1970-01-01
  • 2012-05-10
  • 1970-01-01
相关资源
最近更新 更多