如果 T 是函数,则不要对 T 使用 sizeof
Don't use sizeof for T if T is a function
我几乎有以下结构来检测类型是否可以按值传递:
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
?
部分答案(正如评论中提到的那样,不清楚什么对你不起作用 std::function,它应该是)
您可以组合enable_if_t and is_function 将类型 space 分为两部分,函数和 'the rest' :
#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
}
我无法完全按照您的描述重现问题,但如果我正确理解问题,您可以使用 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;
How can it be modified so that value will contain 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
不是函数时才会被实例化。
How can it be modified so that value will contain 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
、函数类型和所有其他内容都可以轻松透明地处理,不会对您的原始表达式进行任何添加。
我几乎有以下结构来检测类型是否可以按值传递:
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
?
部分答案(正如评论中提到的那样,不清楚什么对你不起作用 std::function,它应该是)
您可以组合enable_if_t and is_function 将类型 space 分为两部分,函数和 'the rest' :
#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
}
我无法完全按照您的描述重现问题,但如果我正确理解问题,您可以使用 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;
How can it be modified so that value will contain 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
不是函数时才会被实例化。
How can it be modified so that value will contain 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
、函数类型和所有其他内容都可以轻松透明地处理,不会对您的原始表达式进行任何添加。