【问题标题】:How to decltype template method C++?如何decltype模板方法C++?
【发布时间】:2020-05-23 01:06:57
【问题描述】:

我通过实现验证的概念编写接口。

常规方法没有问题:

// Interface realization
struct Realization
{
    int* TestMethod(const std::string& aStr)
    {
        return (int *) aStr.c_str();
    }
};

// Concept
template <typename T>
concept IRealization = std::is_same_v<decltype(&T::TestMethod), int* (T::*)(const std::string&)>;

// and then, for example
void Check()
{
    static_assert(IRealization<Realization>)
}

但是当我尝试为模板方法编写类似的检查时:

// Interface realization
struct Realization
{
    template <typename T>
    int* TemplateMethod(const T& aStr)
    {
        return (int *) aStr.c_str();
    }
};

,我遇到了一个模板方法dectype的问题,因为我不会写

decltype(&RealizationImpl::TemplateMethod)

(查看接口时,不知道要替换的类型)

请告诉我,我能否以某种方式获得没有类型的模板函数的签名,或者以其他方式解决我的问题?谢谢!

【问题讨论】:

  • 没有实例化就无法获得函数原型。您需要向该概念添加另一个模板参数,因为该概念不需要测试T,而是T&lt;U&gt;T&lt;U1&gt; 可能会成功,但 T&lt;U2&gt; 可能会失败。
  • 另外附注这个问题:TestMethod 应该完成什么?最好的情况是,如果对齐匹配,它会返回一个指针,在将其转换回char* 之前不允许取消引用;最坏的情况是,如果对齐不匹配,它会返回一个具有未指定值且永远不可用的指针。
  • template &lt;typename T&gt; template &lt;typename U&gt; concept IRealization = std::is_same_v&lt;decltype(&amp;T::template TestMethod&lt;U&gt;), int* (T::*)(const U&amp;)&gt;; 不会编译,所以不确定任何其他方式..
  • @walnut TestMethod 没有逻辑意义,它只是一个例子。你说得对,我应该想出一个更充分的例子

标签: c++ templates template-meta-programming c++20 c++-concepts


【解决方案1】:

你不应该写这样的概念。一个概念永远不应该检查像具有精确签名的成员函数这样具体的东西。相反,一个概念应该说,给定所讨论类型的实例,我应该能够执行i.memberFunc(...),其中... 是参数列表。

例如,你的“IRealization”概念(请不要在概念前面加上I。概念是不是接口)应该说“T必须有一个成员函数,它可以是在给定 std::string 参数的情况下调用,并产生可转换为 int 的东西。”看起来像:

template <typename T>
concept IRealization = requires(T t, std::string str)
{
  { t.TestMethod(str) } -> convertible_to<int>;
};

这允许用户提供TestMethod,例如,std::string_view 而不是std::string。对类型进行如此难以置信的限制是没有意义的。

检查T 的概念是否具有可使用某种类型U 调用的成员函数,必须在TU 上进行模板化:

template <typename T, typename U>
concept IRealization = requires(T t, U u)
{
  { t.TestMethod(u) } -> convertible_to<int>;
};

【讨论】:

  • "概念不是接口" - 嗯,与 Java 接口等相比,它们似乎确实能够实现类似的类型安全和选择。请详细说明一下好吗?此外,我对concept 的语法非常陌生,但我相信在您的第二个sn-p 中,; 是一个错字。不过我可能错了。
  • @Fureeish:“嗯,与 Java 接口等相比,它们似乎确实能够实现类似的类型安全和选择。” 最大的区别在于:哪些接口类型实现被定义为类型本身的显式部分。相比之下,您无法查看一个类型并知道它满足哪些概念。实际上,您可以定义旧类型满足的新概念;这对于接口是不可能的,除非您将接口插入到类型层次结构中。
  • 还有更多。例如,一个概念不需要对一种类型进行操作。你可以有一个概念说“这种类型的尺寸比这种类型大”。
【解决方案2】:

在概念中添加另一种类型有什么问题?

// Concept
template <typename T, typename U>
concept IRealization = std::is_same_v<decltype(&T::template TestMethod<U>), int* (T::*)(const U&)>;

例如。

你甚至可以通过创建 typedef 来让它更漂亮 -

template<typename T, typename U>
using FuncT = decltype(&T::template TestMethod<U>);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-22
    相关资源
    最近更新 更多