4

我正在尝试使用 C++20 概念和Eigen 库,但发生了意外行为。具体来说,考虑以下概念,要求类型可以用Eigen::Matrix<double, -1, 1>>对象或对象调用Eigen::Matrix<char, -1, 1>>

template <class FOO_CONCEPT>
concept FooConcept = std::invocable<FOO_CONCEPT, Eigen::Matrix<double, -1, 1>> &&
    std::invocable<FOO_CONCEPT, Eigen::Matrix<char, -1, 1>>;

然后,查看以下结构中的注释行 (*):

struct Foo {
    // template <typename T>    <----    (*)
    void operator()(Eigen::Matrix<double, -1, 1>) {
    }

    void operator()(Eigen::Matrix<float, -1, 1>) {
    }
};

请注意,该类Foo不满足 的要求,FooConcept因为它不能用Eigen::Matrix<char, -1, 1>参数调用。的确:

std::cout << FooConcept<Foo> << std::endl;

打印0。但是,当我切换行注释 (*) 时,即当operator()是模板时,相同的代码会奇怪地打印1. 这是一个错误吗?我使用 Clang 12.0.1 和 GCC 11.1.0 在 Visual Studio Code 上编译代码时得到了这些结果。感谢您提供任何帮助!

PS:线

 std::cout << std::is_convertible<Eigen::Matrix<char, -1, 1>, Eigen::Matrix<float, -1, 1>>()
              << std::endl;

打印1,但Eigen::Matrix<char, -1, 1>不能将对象隐式转换为Eigen::Matrix<float, -1, 1>. 这是另一个错误吗?这是否与上述问题相关?


编辑1:我注意到通过定义

struct FooImplicit {
    void operator()(Eigen::Matrix<char, -1, 1>) {
    }
};

FooImplicit结构实际上满足FooConcept,如果替换为 ,也会发生同样char的情况double。这看起来与两种 Eigen 类型的可转换性有关——见 PS

如何在不允许隐式转换的情况下表达我想要的约束?也就是说,FooConcept必须只允许operator() 至少重载两次的类,一次 withEigen::Matrix<double, -1, 1>和一次 with Eigen::Matrix<char, -1, 1>。这可以做到吗?

另外,如果我定义函数

void func(FooConcept auto x) {}

我尝试将其称为func(Foo());保留行 (*) 注释,我收到以下编译错误:

[build] [...]: note: because 'Foo' does not satisfy 'FooConcept'
[build] void func(FooConcept auto x) {
[build]               ^
[build] [...]: note: because 'std::invocable<Foo, Eigen::Matrix<char, -1, 1> >' evaluated to false

这是因为编译器无法明确选择要调用的重载吗?如果是,为什么错误消息不更明确?对我来说,它看起来就像编译器注意到它Foo有两个成员函数,一个是正确的,而另一个不是。


编辑2:我设法回答了这篇文章中的一半问题。但是,我仍然对我从编译器得到的错误信息感到好奇。

4

1 回答 1

4

is_convertable仅确定是否存在过载并且可以明确地找到。在 Eigen 的情况下,这些类型之间存在重载转换,但主体有一个static_assert.

is_convertable说它有效之前不会实例化转换操作的主体。这是有意的,以允许 C++ 重载解析不需要编译大量代码。

为了使您的特征起作用,需要重写 Eigen 以支持“SFINAE”友好的方法和转换运算符。

您的测试失败是因为 char 矩阵转换为两者,这是不明确的,因此特征失败。这不是你认为它失败的原因。

添加template<class T>不考虑重载的方法(无法推断出 T),因此明确选择了转换为浮点数组。

于 2021-05-03T23:33:10.513 回答