CTAD 无法针对模板基类成功。

huangapple go评论116阅读模式
英文:

CTAD fails for templated base class

问题

考虑以下简单的结构。我从Entity派生了一个类类型EntityView,它允许我指定一个分配器(如果我想要的话),如果我不指定,它应该回退到默认的模板参数。然而,编译器抱怨它无法推断模板参数:

#include <iostream>
#include <stdexcept>
#include <string>
#include <memory>

template <typename StringType = std::string>
struct Entity {
    Entity(int) {
        std::cout << "Hello World!" << std::endl;
    }
};

template <typename Allocator = std::allocator<int>>
struct EntityView : public Entity<std::basic_string<char, std::char_traits<char>, Allocator>> {
    using Entity<std::basic_string<char, std::char_traits<char>, Allocator>>::Entity;
};

int main() {
    EntityView myview{2};
}

产生的错误信息(gcc):

<source>: In function 'int main()':
<source>:19:24: error: class template argument deduction failed:
   19 |     EntityView myview{2};
      |                        ^
<source>:19:24: error: no matching function for call to 'EntityView(int)'
<source>:14:8: note: candidate: 'template<class Allocator> EntityView()-> EntityView<Allocator>'
   14 | struct EntityView : public Entity<std::basic_string<char, std::char_traits<char>, Allocator>> {
      |        ^~~~~~~~~~
<source>:14:8: note:   template argument deduction/substitution failed:
<source>:19:24: note:   candidate expects 0 arguments, 1 provided
   19 |     EntityView myview{2};
      |                        ^
<source>:14:8: note: candidate: 'template<class Allocator> EntityView(EntityView<Allocator>)-> EntityView<Allocator>'
   14 | struct EntityView : public Entity<std::basic_string<char, std::char_traits<char>, Allocator>> {
      |        ^~~~~~~~~~
<source>:14:8: note:   template argument deduction/substitution failed:
<source>:19:24: note:   mismatched types 'EntityView<Allocator>' and 'int'
   19 |     EntityView myview{2};
      |                        ^

问题似乎在于它尝试进行类模板参数推断(CTAD),但在构造函数中没有什么可以从中推导出来,也不在继承的类中。是否有任何方法让编译器接受默认的模板参数而不是尝试推断它?

英文:

Consider the following simple construct. I derive a class type EntityView from Entity which allows me to specify an allocator if I want to, and if I don't it should fall back to the defaulted template parameter. Yet the compiler complains that it can't derive template arguments:

Demo

#include &lt;iostream&gt;
#include &lt;stdexcept&gt;
#include &lt;string&gt;
#include &lt;memory&gt;

template &lt;typename StringType = std::string&gt;
struct Entity {
    Entity(int) {
        std::cout &lt;&lt; &quot;Hello World!&quot; &lt;&lt; std::endl;
    }
};

template &lt;typename Allocator = std::allocator&lt;int&gt;&gt;
struct EntityView : public Entity&lt;std::basic_string&lt;char, std::char_traits&lt;char&gt;, Allocator&gt;&gt; {
    using Entity&lt;std::basic_string&lt;char, std::char_traits&lt;char&gt;, Allocator&gt;&gt;::Entity;
};

int main() {
    EntityView myview{2};
}

Yields (gcc):

&lt;source&gt;: In function &#39;int main()&#39;:
&lt;source&gt;:19:24: error: class template argument deduction failed:
   19 |     EntityView myview{2};
      |                        ^
&lt;source&gt;:19:24: error: no matching function for call to &#39;EntityView(int)&#39;
&lt;source&gt;:14:8: note: candidate: &#39;template&lt;class Allocator&gt; EntityView()-&gt; EntityView&lt;Allocator&gt;&#39;
   14 | struct EntityView : public Entity&lt;std::basic_string&lt;char, std::char_traits&lt;char&gt;, Allocator&gt;&gt; {
      |        ^~~~~~~~~~
&lt;source&gt;:14:8: note:   template argument deduction/substitution failed:
&lt;source&gt;:19:24: note:   candidate expects 0 arguments, 1 provided
   19 |     EntityView myview{2};
      |                        ^
&lt;source&gt;:14:8: note: candidate: &#39;template&lt;class Allocator&gt; EntityView(EntityView&lt;Allocator&gt;)-&gt; EntityView&lt;Allocator&gt;&#39;
   14 | struct EntityView : public Entity&lt;std::basic_string&lt;char, std::char_traits&lt;char&gt;, Allocator&gt;&gt; {
      |        ^~~~~~~~~~
&lt;source&gt;:14:8: note:   template argument deduction/substitution failed:
&lt;source&gt;:19:24: note:   mismatched types &#39;EntityView&lt;Allocator&gt;&#39; and &#39;int&#39;
   19 |     EntityView myview{2};
      |                        ^

The problem seems to be that it is trying to do CTAD, however there's nothing to be derived from the constructor, also not in the inherited class. Is there any way to have the compiler just accept the default template argument instead of trying to deduce it?

答案1

得分: 4

只定义一个通用的扣除指南:

#include <iostream>
#include <stdexcept>
#include <string>
#include <memory>

template <typename StringType = std::string>
struct Entity {
    Entity(int) {
        std::cout << "你好,世界!" << std::endl;
    }
    template <typename T>
    Entity(T) {
        std::cout << "模板" << std::endl;
    }
    template<typename... Args>
    Entity(Args&&...) {
        std::cout << "可变参数" << std::endl;
    }
};

template <typename Allocator = std::allocator<int>>
struct EntityView : public Entity<std::basic_string<char, std::char_traits<char>, Allocator>> {
    using Entity<std::basic_string<char, std::char_traits<char>, Allocator>>::Entity;
};

template<typename... Args>
EntityView(Args&&...) -> EntityView<>;

int main() {
  { EntityView myview{2}; }
  { EntityView myview{2.}; }
  { EntityView myview{2, 3}; }
}
英文:

Just define a universal deduction guide:

#include &lt;iostream&gt;
#include &lt;stdexcept&gt;
#include &lt;string&gt;
#include &lt;memory&gt;

template &lt;typename StringType = std::string&gt;
struct Entity {
    Entity(int) {
        std::cout &lt;&lt; &quot;Hello World!&quot; &lt;&lt; std::endl;
    }
    template &lt;typename T&gt;
    Entity(T) {
        std::cout &lt;&lt; &quot;template&quot; &lt;&lt; std::endl;
    }
    template&lt;typename... Args&gt;
    Entity(Args&amp;&amp;...) {
        std::cout &lt;&lt; &quot;variadic&quot; &lt;&lt; std::endl;
    }
};

template &lt;typename Allocator = std::allocator&lt;int&gt;&gt;
struct EntityView : public Entity&lt;std::basic_string&lt;char, std::char_traits&lt;char&gt;, Allocator&gt;&gt; {
    using Entity&lt;std::basic_string&lt;char, std::char_traits&lt;char&gt;, Allocator&gt;&gt;::Entity;
};

template&lt;typename... Args&gt;
EntityView(Args&amp;&amp;...) -&gt; EntityView&lt;&gt;;

int main() {
  { EntityView myview{2}; }
  { EntityView myview{2.}; }
  { EntityView myview{2, 3}; }
}

huangapple
  • 本文由 发表于 2023年7月3日 22:55:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/76605896.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定