C++ 确定最便宜参数类型的编译时方法
我有一个像这样的模板C++ 确定最便宜参数类型的编译时方法,c++,stl,C++,Stl,我有一个像这样的模板 template <typename T> class Foo { public: Foo(const T& t) : _t(t) {} private: const T _t; }; 模板类Foo { 公众: Foo(const T&T):\u T(T){ 私人: 康斯特; }; 在参数类型像bool或char这样微不足道的情况下,是否有一种精明的模板元编程方法来避免使用const引用?比如: Foo(stl::smarter_ar
template <typename T> class Foo
{
public:
Foo(const T& t) : _t(t) {}
private:
const T _t;
};
模板类Foo
{
公众:
Foo(const T&T):\u T(T){
私人:
康斯特;
};
在参数类型像bool或char这样微不足道的情况下,是否有一种精明的模板元编程方法来避免使用const引用?比如:
Foo(stl::smarter_argument<T>::type t) : _t(t) {}
Foo(stl::smarter_参数::类型t):_t(t){
我认为正确的类型特征是是标量。这项工作如下:
template<class T, class = void>
struct smarter_argument{
using type = const T&;
};
template<class T>
struct smarter_argument<T, std::enable_if_t<std::is_scalar_v<T>>> {
using type = T;
};
模板
结构智能参数{
使用type=const T&;
};
模板
结构智能参数{
使用类型=T;
};
编辑:
以上内容仍然有点老套,感谢@HolyBlackCat提醒我这个更简洁的版本:
template<class T>
using smarter_argument_t = std::conditional_t<std::is_scalar_v<T>, T, const T&>;
模板
使用更智能的参数\u t=std::conditional\u t;
我会使用C++20关键字requires
。就这样,
#include <iostream>
template<typename T>
class Foo
{
public:
Foo(T t) requires std::is_scalar_v<T>: _t{t} { std::cout << "is scalar" <<std::endl; }
Foo(const T& t) requires (not std::is_scalar_v<T>): _t{t} { std::cout << "is not scalar" <<std::endl;}
private:
const T _t;
};
class cls {};
int main()
{
Foo{true};
Foo{'d'};
Foo{3.14159};
cls c;
Foo{c};
return 0;
}
我建议使用sizeof(size\u t)
(或sizeof(ptrdiff\u t)
)返回与您的机器相关的“典型”大小,希望此大小的任何变量都能放入寄存器。在这种情况下,您可以通过值安全地传递它。此外,正如@n314159所建议的那样(参见本文末尾的评论),确保变量也是可复制的非常有用
下面是一个C++17演示:
#include <array>
#include <ccomplex>
#include <iostream>
#include <type_traits>
template <typename T>
struct maybe_ref
{
using type = std::conditional_t<sizeof(T) <= sizeof(size_t) and
std::is_trivially_copyable_v<T>, T, const T&>;
};
template <typename T>
using maybe_ref_t = typename maybe_ref<T>::type;
template <typename T>
class Foo
{
public:
Foo(maybe_ref_t<T> t) : _t(t)
{
std::cout << "is reference ? " << std::boolalpha
<< std::is_reference_v<decltype(t)> << std::endl;
}
private:
const T _t;
};
int main()
{
// with my machine
Foo<std::array<double, 1>> a{std::array<double, 1>{}}; // <- by value
Foo<std::array<double, 2>> b{std::array<double, 2>{}}; // <- by ref
Foo<double> c{double{}}; // <- by value
Foo<std::complex<double>> d{std::complex<double>{}}; // <- by ref
}
#包括
#包括
#包括
#包括
模板
结构可能参考
{
使用type=std::conditional_tI不会担心它,如果函数很小,编译器将内联它,引用甚至不存在。如果函数很大,将整数包装到引用中的微小成本将很小。我猜,更担心的是完美转发,而不是避免对小数据类型的引用在大多数情况下,按r值传递引用可以优化为按值传递。需要记住的是,答案中没有指出:您所做的将破坏隐式推导指南。如果您关心为Foo
@TarekDa工作的类模板参数推导,请记住编写显式推导指南khran scalar包含的指针和枚举不是基本的,应该通过值IMO传递。我不熟悉class=void语法。这是否意味着它可以是任何东西,因为它被忽略了?=void
意味着它有一个默认类型为void,所以使用智能参数实际上是智能参数
。我为这个参数留下了一个名称,因为我们不需要它,因此class=void
没有名称。重要的是std::enable_if_t
在启用的情况下也必须是void才能匹配默认类型。可以使用更智能的参数=std::conditional\t;
std::condition将其简化为模板nal_t
和std::enable_if_t
可以通过使用C++20概念来大大简化。请注意,没有“计算机的指针大小”这样的东西:struct Foo{void bar(){};int i;};std::cout@BlueTune有趣,谢谢您的评论。另请参见您的示例:指针和函数指针可能有不同的大小。即使不同的指针也可能有不同的大小。其目的是获得机器的“典型”大小。我已将不明确的sizeof(void*)替换为sizeof(size\t)@Picaud也许你想使用你可能还想检查T
是否可以复制。例如,在我的平台上,一个共享指针的大小只有size\u T
的两倍,并且它可以用一个指针来实现,使其降到相同的大小。但是你肯定想通过const ref而不是按值。@n314159是的,这将是一个改进。如果在我的答案中包含您的想法,您可以吗?很有趣。使用const auto&作为构造函数参数有好处吗?@cppguiy:我很高兴您问这个问题。如果我将参数“const auto&t”替换为“const t&t”,代码将无法编译。错误如下:“…对'Foo'的模板参数的不明确推断…”。。。"。也许你能找到原因?@cppguy:我们的讨论导致了我提出的一个问题。你可以找到。概念在这里是多余的,而且比替代品更难阅读。@S.S.安妮:使用C++20概念从来都不是多余的。它只是很优雅。我到目前为止看到的替代品更难阅读,因为使用嵌套模板。
#include <array>
#include <ccomplex>
#include <iostream>
#include <type_traits>
template <typename T>
struct maybe_ref
{
using type = std::conditional_t<sizeof(T) <= sizeof(size_t) and
std::is_trivially_copyable_v<T>, T, const T&>;
};
template <typename T>
using maybe_ref_t = typename maybe_ref<T>::type;
template <typename T>
class Foo
{
public:
Foo(maybe_ref_t<T> t) : _t(t)
{
std::cout << "is reference ? " << std::boolalpha
<< std::is_reference_v<decltype(t)> << std::endl;
}
private:
const T _t;
};
int main()
{
// with my machine
Foo<std::array<double, 1>> a{std::array<double, 1>{}}; // <- by value
Foo<std::array<double, 2>> b{std::array<double, 2>{}}; // <- by ref
Foo<double> c{double{}}; // <- by value
Foo<std::complex<double>> d{std::complex<double>{}}; // <- by ref
}