我的应用程序遇到问题,我想断言函数应用程序将被编译器拒绝。有没有办法通过 SFINAE 检查一下?
例如,假设我想验证
std::transform
到 const
范围是非法的。这是我到目前为止所拥有的:
#include <algorithm>
#include <functional>
#include <iostream>
namespace ns
{
using std::transform;
template<typename Iterator1, typename Iterator2, typename UnaryFunction>
struct valid_transform
{
static Iterator1 first1, last1;
static Iterator2 first2;
static UnaryFunction f;
typedef Iterator2 yes_type;
typedef struct {yes_type array[2];} no_type;
static no_type transform(...);
static bool const value = sizeof(transform(first1, last1, first2, f)) == sizeof(yes_type);
};
}
int main()
{
typedef int *iter1;
typedef const int *iter2;
typedef std::negate<int> func;
std::cout << "valid transform compiles: " << ns::valid_transform<iter1,iter1,func>::value << std::endl;
std::cout << "invalid transform compiles: " << ns::valid_transform<iter1,iter2,func>::value << std::endl;
return 0;
}
不幸的是,我的特质既拒绝合法案件,也拒绝非法案件。结果:
$ g++ valid_transform.cpp
$ ./a.out
valid transform compiles: 0
invalid transform compiles: 0
您的问题类似于 SFINAE + sizeof = 检测表达式是否编译。
该答案的摘要:
sizeof
评估传递给它的表达式的类型,包括实例化函数模板,但它不会生成函数调用。这就是 Lol4t0 观察到即使 sizeof(std::transform(iter1(), iter1(), iter2(), func()))
不编译,std::transform(iter1(), iter1(), iter2(), func())
也能编译的原因。
您的具体问题可以通过评估 Lol4t0 答案中的模板来解决,以获取要提供给
std::transform
的任何输出范围。然而,在模板中验证函数调用是否会编译的一般问题似乎无法通过 sizeof + SFINAE
技巧来解决。 (它需要一个可从运行时函数调用导出的编译时表达式)。
您可能想尝试 ConceptGCC 看看这是否允许您以更方便的方式表达必要的编译时检查。
在我的回答中,我想关注问题,如果给定迭代器常量,如何确定: 提到了
std::is_const
,但在这种情况下它对我不起作用(gcc 4.7)。
我想,它的实现就像
template <typename T>
struct is_const
{
enum {value = false };
};
template <typename T>
struct is_const<const T>
{
enum {value = true };
};
现在,无法使用此结构检查引用类型,它们不会匹配专业化,因为
const T
将匹配int& const
,即对int的常量引用,而不是const int&
,即对常量int的引用 ,首先没有任何意义。
好的,但是我们可以确定迭代器是否与以下结构保持一致:
template <typename Iterator>
struct is_iterator_constant
{
typedef char yes_type;
typedef struct{ char _[2];} no_type;
template <typename T>
static no_type test(T&);
template <typename T>
static yes_type test(...);
enum {value = sizeof(test<typename std::iterator_traits<Iterator>::value_type>(*Iterator())) == sizeof(yes_type) };
};
C++20 概念使检查表达式有效性变得更加容易。您使用 member detector idiom 的解决方案是有效的,但比带有
concept
表达式的 requires
更困难且效率低得多:
template <typename Iter1, typename Iter2, typename UnaryFunction>
concept valid_transform = requires (Iter1 first1, Iter1 last1, Iter2 first2, UnaryFunction f) {
transform(first1, last1, first2, f);
};
如果您真的认真对待这个约束,您可能会构建一个
concept
,其中包含 std::ranges::transform
函数模板的所有约束。