可变数量的参数,没有宏或初始化列表的相同特定类型
variable number of arguments, same specific type without macro or initializer-list
我正在尝试做类似于 C++11 variable number of arguments, same specific type 的事情,但我有自己的类型:
struct Foo
{
Foo(int) {}
Foo(int, int) {}
};
一堆重载
void f() {}
void f(const Foo&) {}
void f(const Foo&, const Foo&) {}
// etc. ... as many f() overloads as needed ...
按需工作:f(); f(1); f(1, 2); f(1, { 2, 3 });
。
除了重载,我还可以使用 std::initializer_list<>
和 {}
语法(建议 here):
void g_(std::initializer_list<Foo>) {}
g_({}); g_({ 1 }); g_({ 1, 2 }); g_({ 1, { 2, 3 } });
但是有一组额外的 {}
(是的,它只是两个字符)。要完全匹配 f()
的语法,请使用宏:
#define g(...) g_({__VA_ARGS__})
g(); g(1); g(1, 2); g(1,{ 2, 3 });
(由于遗留或生成的代码,可能需要完全匹配 f()
的语法。...而且它—arguably—只是 "looks better"。)
但我找不到使可变参数模板工作的方法
void h() { }
template<typename... T>
void h(const Foo&, T...) { }
h()
、h(1)
和 h(1, 2)
可以工作,但是 h(1, {2, 3})
无法编译,因为编译器无法确定 {2, 3}
的类型它可以与 f()
和 g_()
.
有没有办法让 f()
在没有多重重载的情况下工作?或者 g()
不用宏也能工作? g()
非常 接近(只有一个函数,没有模板魔术),但是有那个宏 ...
如果你想要一堆 Foo
,并且你想要允许 braced-init-lists,那么你应该这样做:
void foo(std::initializer_list<Foo> );
是的,这需要一套额外的牙套。不,您不应该使用宏来省略这两个字符。
您不能在此处使用可变参数模板,因为 braced-init-list 不是 表达式 并且它没有 type,所以不能推导。
{}
要求您正在初始化特定类型的内容。
C++11 变量参数要求您的类型是扣除类型。
这些是相反的要求。
现在我可以生成一个包含一组 ()
重载的对象,最多可达某个大的有限数。
namespace details {
template<std::size_t, class T>
using ignore_index=T;
template<class T, class Count, class Base>
struct linear_overload_count;
template<class T, std::size_t I0, std::size_t...Is, class Base>
struct linear_overload_count<T, std::index_sequence<I0,Is...>, Base>:
linear_overload_count<T, std::index_sequence<Is...>, Base>
{
using linear_overload_count<T, std::index_sequence<Is...>, Base>::operator();
using linear_overload_count<T, std::index_sequence<Is...>, Base>::linear_overload_count;
std::result_of_t<
Base const&(T const&, ignore_index<Is,T>const&...)
>
operator()(T const& t0, ignore_index<Is,T>const&...ts) const {
return Base::operator()(t0, ts...);
}
linear_overload_count()=default;
linear_overload_count(linear_overload_count const&)=default;
linear_overload_count(linear_overload_count &&)=default;
linear_overload_count& operator=(linear_overload_count const&)=default;
linear_overload_count& operator=(linear_overload_count &&)=default;
};
template<class T, class Base>
struct linear_overload_count<T, std::index_sequence<>, Base>:
Base
{
using Base::Base;
linear_overload_count(Base&& b):Base(std::move(b)) {}
linear_overload_count(Base const& b):Base(b) {}
std::result_of_t<
Base const&()
>
operator()() const {
return Base::operator()();
}
linear_overload_count()=default;
linear_overload_count(linear_overload_count const&)=default;
linear_overload_count(linear_overload_count &&)=default;
linear_overload_count& operator=(linear_overload_count const&)=default;
linear_overload_count& operator=(linear_overload_count &&)=default;
};
}
template<class T, std::size_t N, class Base>
using linear_overload_Ts = details::linear_overload_count<T, std::make_index_sequence<N>, Base>;
auto count_args_impl = [](auto&&...args) { std::cout << sizeof...(args) << "\n"; };
struct bob {
int x,y;
};
using count_bobs_t = linear_overload_Ts< bob, 3, decltype(count_args_impl) >;
count_bobs_t const bobs = count_args_impl;
int main() {
bobs();
bobs({}, {}, {1,2});
}
现在,通过更改 to 100
.
上方的数字 3
,我们最多可以在 bobs
中进行 100 次重载
注意,如果你打了100多个,your compiler will die。这可以通过二叉树继承而不是线性继承来解决,但我不会被打扰。
此外,此技术会减慢编译速度。
注意Base
必须是类型。您可以像上面那样使用 lambda 转发到您的模板函数(给它们不同的名称)、手动函数对象或其他任何东西。
如果不借助在调用中命名的类型(因此,使用 ADL 查找生成的函数),我无法解决使用此技术创建函数而不是函数对象的问题。函数对象不像函数那样参与重载决议,这可能是个问题。
添加额外的一组 {}
。
似乎也需要做很多工作
我正在尝试做类似于 C++11 variable number of arguments, same specific type 的事情,但我有自己的类型:
struct Foo
{
Foo(int) {}
Foo(int, int) {}
};
一堆重载
void f() {}
void f(const Foo&) {}
void f(const Foo&, const Foo&) {}
// etc. ... as many f() overloads as needed ...
按需工作:f(); f(1); f(1, 2); f(1, { 2, 3 });
。
除了重载,我还可以使用 std::initializer_list<>
和 {}
语法(建议 here):
void g_(std::initializer_list<Foo>) {}
g_({}); g_({ 1 }); g_({ 1, 2 }); g_({ 1, { 2, 3 } });
但是有一组额外的 {}
(是的,它只是两个字符)。要完全匹配 f()
的语法,请使用宏:
#define g(...) g_({__VA_ARGS__})
g(); g(1); g(1, 2); g(1,{ 2, 3 });
(由于遗留或生成的代码,可能需要完全匹配 f()
的语法。...而且它—arguably—只是 "looks better"。)
但我找不到使可变参数模板工作的方法
void h() { }
template<typename... T>
void h(const Foo&, T...) { }
h()
、h(1)
和 h(1, 2)
可以工作,但是 h(1, {2, 3})
无法编译,因为编译器无法确定 {2, 3}
的类型它可以与 f()
和 g_()
.
有没有办法让 f()
在没有多重重载的情况下工作?或者 g()
不用宏也能工作? g()
非常 接近(只有一个函数,没有模板魔术),但是有那个宏 ...
如果你想要一堆 Foo
,并且你想要允许 braced-init-lists,那么你应该这样做:
void foo(std::initializer_list<Foo> );
是的,这需要一套额外的牙套。不,您不应该使用宏来省略这两个字符。
您不能在此处使用可变参数模板,因为 braced-init-list 不是 表达式 并且它没有 type,所以不能推导。
{}
要求您正在初始化特定类型的内容。
C++11 变量参数要求您的类型是扣除类型。
这些是相反的要求。
现在我可以生成一个包含一组 ()
重载的对象,最多可达某个大的有限数。
namespace details {
template<std::size_t, class T>
using ignore_index=T;
template<class T, class Count, class Base>
struct linear_overload_count;
template<class T, std::size_t I0, std::size_t...Is, class Base>
struct linear_overload_count<T, std::index_sequence<I0,Is...>, Base>:
linear_overload_count<T, std::index_sequence<Is...>, Base>
{
using linear_overload_count<T, std::index_sequence<Is...>, Base>::operator();
using linear_overload_count<T, std::index_sequence<Is...>, Base>::linear_overload_count;
std::result_of_t<
Base const&(T const&, ignore_index<Is,T>const&...)
>
operator()(T const& t0, ignore_index<Is,T>const&...ts) const {
return Base::operator()(t0, ts...);
}
linear_overload_count()=default;
linear_overload_count(linear_overload_count const&)=default;
linear_overload_count(linear_overload_count &&)=default;
linear_overload_count& operator=(linear_overload_count const&)=default;
linear_overload_count& operator=(linear_overload_count &&)=default;
};
template<class T, class Base>
struct linear_overload_count<T, std::index_sequence<>, Base>:
Base
{
using Base::Base;
linear_overload_count(Base&& b):Base(std::move(b)) {}
linear_overload_count(Base const& b):Base(b) {}
std::result_of_t<
Base const&()
>
operator()() const {
return Base::operator()();
}
linear_overload_count()=default;
linear_overload_count(linear_overload_count const&)=default;
linear_overload_count(linear_overload_count &&)=default;
linear_overload_count& operator=(linear_overload_count const&)=default;
linear_overload_count& operator=(linear_overload_count &&)=default;
};
}
template<class T, std::size_t N, class Base>
using linear_overload_Ts = details::linear_overload_count<T, std::make_index_sequence<N>, Base>;
auto count_args_impl = [](auto&&...args) { std::cout << sizeof...(args) << "\n"; };
struct bob {
int x,y;
};
using count_bobs_t = linear_overload_Ts< bob, 3, decltype(count_args_impl) >;
count_bobs_t const bobs = count_args_impl;
int main() {
bobs();
bobs({}, {}, {1,2});
}
现在,通过更改 to 100
.
3
,我们最多可以在 bobs
中进行 100 次重载
注意,如果你打了100多个,your compiler will die。这可以通过二叉树继承而不是线性继承来解决,但我不会被打扰。
此外,此技术会减慢编译速度。
注意Base
必须是类型。您可以像上面那样使用 lambda 转发到您的模板函数(给它们不同的名称)、手动函数对象或其他任何东西。
如果不借助在调用中命名的类型(因此,使用 ADL 查找生成的函数),我无法解决使用此技术创建函数而不是函数对象的问题。函数对象不像函数那样参与重载决议,这可能是个问题。
添加额外的一组 {}
。