您好我试图在C ++ 11中实现类似C ++概念的功能(C ++ 14)。我的想法只是为std::for_each()
算法编写包装函数,我只是检查第三个参数是否是一个函数。所以我编写了以下代码,但是我无法按原样编译它。我正在使用Ubuntu12.04和gcc4.8.1。
test_1.cpp
#include<type_traits>
#include<iostream>
#include<vector>
#include<algorithm>
void display(int& val) {
std::cout <<val<<std::endl;
}
template<typename T>
constexpr bool Is_valid_function(T& a) {
return std::is_function<T>::value;
}
template<typename T>
void check_valid_function(T& a) {
static_assert(Is_valid_function(a), "Not The Valid Function");
}
template <class InputIterator, class Function>
Function my_for_each(InputIterator first, InputIterator last, Function f) {
/* Concept Like Implementation to just check whether f is function or not */
check_valid_function(f);
return for_each(first, last, f) ;
}
void learn_static_assert_and_typetraits(void)
{
std::vector<int> vec_x{1,2,3,4,5};
my_for_each(vec_x.begin(), vec_x.end(), display);
}
int main(int argc, const char* argv[]) {
learn_static_assert_and_typetraits();
return 0;
}
我收到以下编译错误,从中我可以看到static_assert()
失败,这是不正确的,因为display
是有效的函数。
test_3.cpp: In instantiation of ‘void check_valid_function(T&) [with T = void (*)(int&)]’: test_3.cpp:27:26: required from ‘Function my_for_each(InputIterator, InputIterator, Function) [with InputIterator = __gnu_cxx::__normal_iterator >; Function = void (*)(int&)]’ test_3.cpp:35:50: required from here test_3.cpp:19:3: error: static assertion failed: Not The Valid Function static_assert(Is_valid_function(a), "Not The Valid Function"); ^
但是,如果我对其他type_traits函数做同样的事情,我会收到以下错误,这是正确的和预期的。
test_2.cpp
#include<type_traits>
template<typename T>
constexpr bool Is_floating_point(T& a) {
return std::is_floating_point<T>::value;
}
template<typename T>
void f(T& a) {
static_assert(Is_floating_point(a), "Non-Float Type Data");
}
void learn_static_assert_and_typetraits(void) {
float y{10.0};
f(y);
int x{100};
f(x);
}
int main(int argc, const char* argv[]) {
learn_static_assert_and_typetraits();
return 0;
}
test_2.cpp: In instantiation of ‘void f(T&) [with T = int]’: test_2.cpp:19:6: required from here test_2.cpp:11:3: error: static assertion failed: Non-Float Type Data static_assert(Is_floating_point(a), "Non-Float Type Data"); ^
所以,我想了解为什么我的第一个程序不能正常工作,我的代码/理解中是否存在错误,或者是其他问题。我希望上述数据足以理解我的问题。但是,如果有人想要一些额外的数据,请告诉我。
答案 0 :(得分:2)
问题在于:
template <class InputIterator, class Function>
Function my_for_each(InputIterator first, InputIterator last, Function f)
通过:
调用my_for_each(vec_x.begin(), vec_x.end(), display);
这会将Function
(my_for_each
)推断为函数指针;对
void display(int& val)
推导出的类型为void(*)(int&)
。然而,类型特征std::is_function
检查传递的类型是函数类型,而不是函数指针类型。
一种解决方案是删除指针:
template<typename T>
constexpr bool Is_valid_function(T& a) {
return std::is_function<typename std::remove_pointer<T>::type>::value;
}
但是,正如clang ++所揭示的那样,这还不够:
template<typename T>
void check_valid_function(T& a) {
static_assert(Is_valid_function(a), "Not The Valid Function");
}
a
作为函数参数(即使check_valid_function
为constexpr
!)不是编译时常量,因此它可能不会出现在常量表达式(在函数体内)。因此,Is_valid_function(a)
可能不会显示为static_assert
的检查。也许可以使用与declval
类似的东西,例如
static_assert(Is_valid_function( declval<T&>() ), "Not The Valid Function");
但遗憾的是,declval
不 constexpr
,我不知道如何编写constexpr
版本。所以,你可以改为传递一个指针:
static_assert(Is_valid_function(static_cast<T*>(nullptr)),
"Not a valid function");
为此,您需要重写Is_valid_function
,如下所示:
template<typename T>
constexpr bool Is_valid_function(T*) {
return std::is_function<typename std::remove_pointer<T>::type>::value;
}
注意:这里传递的参数是指向函数的指针的指针,但参数T*
推导为T
为指向函数的指针,如前所述(因此签名中的更改)。如果选择此解决方案,您可能希望在函数名称中反映出来。
其他问题:
依赖ADL标准库算法
return for_each(first, last, f) ;
据我所知,这依赖于ADL。但是迭代器(和函数)不需要在命名空间std
中(即使对于vector::iterator
等),所以你不应该依赖于ADL:
return std::for_each(first, last, f);
对不需要修改参数的函数使用非const引用,例如
constexpr bool Is_valid_function(T& a)
如果您不需要修改参数,则应该通过值或const引用传递它,例如
constexpr bool Is_valid_function(T const& a)
“错误检查”如果此代码仅用于教育目的,则不是问题。但是,在尝试检查参数是否对标准库算法有效时,检查传递的参数是否为函数类型是“错误检查”。您应该检查f(*first)
是否格式正确。这允许函数对象并检查参数类型是否为“有效”。