我接近跟随struct检测是否可以通过值传递类型:
template <class T>
struct should_be_passed_by_value {
static constexpr bool value =
std::is_scalar<T>::value ||
std::is_array<T>::value ||
std::is_reference<T>::value ||
(sizeof(T) <= sizeof(void*));
};
问题是:当我为类C函数指针或std :: function实例化它时,编译器说:
invalid application of 'sizeof' to a function type
(当然)。
如何修改以便value
包含false
?
答案 0 :(得分:9)
如何修改以使值包含false?
任何问题都可以通过额外的间接层来解决。我们已经内置了一些这些。基本上,您希望仅在T
不是函数时才使用小号检查。已经存在一个元函数:std::conditional
。我们可以用它来推迟评估。
小的检查,我们分成了自己的元函数:
template <class T>
struct is_small
: std::integral_constant<bool, (sizeof(T) <= sizeof(void*))>
{ };
然后我们可以将您的条件重写为:
template <class T>
struct should_be_passed_by_value {
static constexpr bool value =
std::is_scalar<T>::value ||
std::is_array<T>::value ||
std::is_reference<T>::value ||
std::conditional_t<
std::is_function<T>::value,
std::false_type,
is_small<T>>::value;
};
这样,is_small<T>
仅在T
不是函数时才被实例化。
答案 1 :(得分:4)
如何修改以使值包含false?
它遵循should_be_passed_by_value
的可能实现(实际上是一个最小的工作示例):
#include<type_traits>
#include<functional>
template <class T, typename = void>
struct should_be_passed_by_value: std::false_type {};
template <class T>
struct should_be_passed_by_value
<T, std::enable_if_t<
(std::is_scalar<T>::value ||
std::is_array<T>::value ||
std::is_reference<T>::value ||
(sizeof(T) <= sizeof(void*)))
>>: std::true_type {};
void f() {}
int main() {
static_assert(should_be_passed_by_value<int>::value, "!");
static_assert(should_be_passed_by_value<char>::value, "!");
static_assert(not should_be_passed_by_value<std::function<void(void)>>::value, "!");
static_assert(not should_be_passed_by_value<void(void)>::value, "!");
static_assert(should_be_passed_by_value<void(*)(void)>::value, "!");
}
基本思想是依靠部分专业化
而且,您实际上不必定义自己的value
数据成员。由于您使用的是C ++ 14,should_be_passed_by_value
可以直接从std::false_type
和std::true_type
继承。
默认情况下,您的类型T
不应按值传递(should_be_passed_by_value
继承自std::false_type
)。
如果T
未通过所有检查,则由于std::enable_if_t
的工作原理而放弃专门化。因此,主要模板被选中,这意味着T
不应该通过值传递
如果T
通过了所有检查,则std::enable_if_t
为void
,并且专业化优先于主要模板。请注意,专门化继承自std::true_type
,这意味着在这种情况下T
应该按值传递。
从示例中可以看出,std::function
,函数类型和所有其他内容都可以轻松透明地处理,而不会添加原始表达式。
答案 2 :(得分:2)
我无法像您描述的那样完全重现问题,但如果我正确理解了问题,您可以使用template specialization来彻底解决此问题。以下示例使用Visual Studio 2015和gcc 4.9进行编译。
#include <type_traits>
// Non-function types
template <class T>
struct should_be_passed_by_value
{
static constexpr bool value =
std::is_scalar<T>::value ||
std::is_array<T>::value ||
std::is_reference<T>::value ||
(sizeof(T) <= sizeof(void*));
};
// Function type
template <class Return, class ... Args>
struct should_be_passed_by_value<Return(Args...)>
{
static constexpr bool value = false; // What value for functions?
};
以下是编译
的一些用例// All of these use cases compile
#include <array>
const auto u = should_be_passed_by_value<std::array<int, 10>>::value;
const auto v = should_be_passed_by_value<int*()>::value;
const auto w = should_be_passed_by_value<int()>::value;
const auto x = should_be_passed_by_value<int(int)>::value;
const auto y = should_be_passed_by_value<int*>::value;
const auto z = should_be_passed_by_value<int>::value;
答案 3 :(得分:0)
部分答案(正如评论中提到的那样,并不清楚std :: function对你有什么用处,它应该是这样的)
您可以将enable_if_t和is_function结合起来,将类型空间划分为两个部分,即函数和其他部分&#39; :
#include <type_traits>
#include <functional>
#include <iostream>
template <class T, class Enable = void>
struct should_be_passed_by_value; // primary case that we will never hit
template <class T>
struct should_be_passed_by_value<T, typename std::enable_if_t<std::is_function<T>::value>>
{
static constexpr bool value = false; // case 0
};
template <class T>
struct should_be_passed_by_value<T, typename std::enable_if_t<!std::is_function<T>::value>>
{
static constexpr bool value =
std::is_scalar<T>::value || // case 1
std::is_array<T>::value || // case 2
std::is_reference<T>::value || // case 3
(sizeof(T) <= sizeof(void *)); /// case 4
};
void testF(){};
int main()
{
std::function<void()> f;
std::cout << "should_be_passed_by_value1 " << should_be_passed_by_value<decltype(testF)>::value << std::endl; // result 0, case 0
std::cout << "should_be_passed_by_value1 " << should_be_passed_by_value<decltype(5)>::value << std::endl; // res 1, case 1
std::cout << "should_be_passed_by_value1 " << should_be_passed_by_value<char[42]>::value << std::endl; // res 1, case 2
std::cout << "should_be_passed_by_value1 " << should_be_passed_by_value<int&>::value << std::endl; // res 1 , case 3
struct Small {char _{2};};
std::cout << "should_be_passed_by_value1 " << should_be_passed_by_value<Small>::value << std::endl; // res 1, case 4
struct Big {char _[16];};
std::cout << "should_be_passed_by_value1 " << should_be_passed_by_value<Big>::value << std::endl; // res 0, case 4
}