【问题标题】:How can I build a function concept with a particular signature?如何构建具有特定签名的函数概念?
【发布时间】:2018-12-16 00:09:11
【问题描述】:

我正在使用概念编写一些通用软件,我想检查结构上是否存在带有 (void)(int,int) 签名的特定函数符号名称。为此,我正在考虑通过模板专业化来解决这个问题,但我有点迷失了。

如果不满足这样的概念,我想要的是可以工作并通过编译时错误:

struct TypeA {
  // Passes concept
  void process (int a ,int b) const {};
};

struct TypeB {
  // Does not pass concept
  void process (float a) const {};
};

struct TestConcepts {
  /* concept code here */
  TestConcepts(T t) {
    process_concept(t.process);
  };
};

int main(void) {
  // Should pass
  TestConcept(TypeA{});
  // Should throw error
  TestConcept(TypeB{});
  return 0;
}

我很难填补空白,但这是我目前所拥有的:

struct TestConcepts {
      /* concept code here */
      struct process_concept {
        process_concept((V*)(IA,IB)){
            if (is_integral<IA>::value && is_integral<IB>::value && is_same<V, void>) {
                return;
            }
            static_assert(false, "You must provide function called process of type (void)(int,int)");
        };
    };
      TestConcepts(T t) {
        process_concept(&t.process);
      };
    };

不幸的是,这不起作用。我怎样才能使这个函数签名正确?

【问题讨论】:

  • 我想说你混合了你的术语,因为你似乎想要的是一个 trait 而不是一个概念(这在 C++ 中意味着完全不同的东西,应该是未来语言规范的句法部分)。
  • 是的,我对这种通用编程的东西很陌生。从文档中听起来,特征和概念与我相关或非常相似。但是我知道一个概念限制了某些“基本接口”可以使用的模板参数的类型。它还承诺非继承类型将具有某些类型的特征。当我说类型时,我将其扩展为结构/类/函数等。我的理解错了吗?
  • 请解释为什么我的问题太宽泛了。我有特定于我正在解决的问题的代码。我有问题询问我的代码签名有什么问题。我解释了可能有一些我不理解的概念,但我展示了我正在努力实现的目标。我花了很多时间尽可能清楚地说明这一点。堆栈溢出是否仅适用于专家?
  • [c++-concepts] 标签建议您想知道如何使用可能在 2020 年推出但尚未成为官方 C++ 标准的提议的概念语言功能来做到这一点。如果您想要一个适用于 C++17 的解决方案,您可能应该删除该标签。
  • 我有点不同意。概念可通过设计模式或 boost 库获得。无论是 c++17 还是 c++20,学习如何正确地完成它们是我想要的。

标签: c++ templates metaprogramming template-meta-programming


【解决方案1】:

使用返回已声明函数指针的函数怎么样?

struct TypeA {
    // Passes concept
    void process (int a ,int b) const {};
};

struct TypeB {
    // Does not pass concept
    void process (float a) const {};
};

template<typename T>
auto TestConcepts(T) -> void(T::*)(int, int) const
{
    return &T::process;
}

int main(void) {
    // Should pass
    TestConcepts(TypeA{});
    // Should throw error
    TestConcepts(TypeB{});
    return 0;
}

输出:

Error(s):

source_file.cpp: In instantiation of ‘void (T::* TestConcepts(T))(int, int) const [with T = TypeB]’:
source_file.cpp:26:23:   required from here
source_file.cpp:19:16: error: cannot convert ‘void (TypeB::*)(float) const’ to ‘void (TypeB::*)(int, int) const’ in return
     return &T::process;
                ^

编辑:更多选项

如果您想包含 void process(long int a, long int b) const;void process(int a, int b, int c=0) const;,就像 aschepler 建议的那样,您可以使用类型特征。

struct TypeA {
    // Passes concept
    void process(int a, int b) const {};
};

struct TypeB {
    // Does not pass concept
    void process(float a) const {};
};

struct TypeC {
    // Passes concept
    void process(long int a, long int b) const {};
};

struct TypeD {
    // Passes concept
    void process(int a, int b, int c = 0) const {};
};

struct TypeE {
    // Does not pass concept
    void process(int a, int b, int c) const {};
};

#include <type_traits>
template<typename T, typename A1, typename A2, typename... An>
typename std::enable_if<
    std::is_integral<A1>::value &&
    std::is_integral<A2>::value
>::type
TestProcess(const T& t, void(T::*)(A1, A2, An...) const) {
    t.process(1, 2);
};

template<typename T>
void TestConcepts(const T& t)
{
    TestProcess(t, &T::process);
}

int main(void) {
    // Passes
    TestConcepts(TypeA{});
    // Throws compilation error
    TestConcepts(TypeB{});
    // Passes
    TestConcepts(TypeC{});
    // Passes
    TestConcepts(TypeD{});
    // Throws compilation error
    TestConcepts(TypeE{});

    return 0;
}

【讨论】:

  • 不错的设计模式!谢谢,这真的很有帮助!
  • 请注意,如果类型具有例如void process(long int a, long int b) const;void process(int a, int b, int c=0) const;,这将失败。这是否正确取决于您想要什么。
  • @aschepler 好点。我还在学习自己。也许你可以提出一个更好的答案?
  • @aschepler 我一直在考虑它,并编辑了解决方案以包含具有类型特征的扩展版本。
猜你喜欢
  • 1970-01-01
  • 2020-05-18
  • 1970-01-01
  • 1970-01-01
  • 2015-09-19
  • 2014-10-07
  • 1970-01-01
  • 1970-01-01
  • 2011-04-29
相关资源
最近更新 更多