我有这个示例代码,它完成了我需要的3参数函数:
GETPARAM
(T (*fn)(P1, P2, ...)
模板仅用于显示通话。)
我尝试用可变参数模板来概括它,用于具有任意数量参数的函数,但没有成功。有可能吗?
该模板可用于任何具有任何返回类型和任意数量参数的GETPARAM<Pn>()
,即时构建参数,为每个参数调用function onEdit()
{
var sheet = SpreadsheetApp.getActive().getSheetByName('Market');
var isNumber = sheet.getRange('E2:E1000').getValue()
if (isNumber
};
。
需要为脚本语言创建绑定系统,从堆栈中获取参数并在完成后调用C ++函数。
答案 0 :(得分:4)
我尝试用可变参数模板来概括它,用于具有任意数量参数的函数,但没有成功。有可能吗?
是;这很简单
template <typename R, typename ... Args>
R BuildArgsN (R(*fn)(Args...))
{ return fn(GETPARAM<Args>()...); }
以下是一个完整的工作示例
#include <iostream>
template<typename T>T GETPARAM(void) { return T(); }
template<>int GETPARAM(void) { return 123; }
template<>double GETPARAM(void) { return 1.2345; }
template<>const char *GETPARAM(void) { return "hello"; }
template <typename R, typename ... Args>
R BuildArgsN (R(*fn)(Args...))
{ return fn(GETPARAM<Args>()...); }
int print3 (int a, double b, char const * c)
{
std::cout << "Print3:" << a << ", " << b << ", " << c << "\n";
return 1;
}
int main ()
{
BuildArgsN(print3);
}
答案 1 :(得分:2)
如果要对GETPARAM
进行调用,则必须在保证特定订单的上下文中展开可变参数包。一个选项是list initialization:
每个初始化子句在任何初始化子句之前都会被排序 在braced-init-list中跟随它。这与之形成鲜明对比 函数调用表达式的参数,这些参数是未排序的。
让我们考虑您给出的示例:您可以展开参数包,在构造代理对象的花括号内部产生#include <iostream>
int pos = 0;// DEBUG: observe the order of `GETPARAM` calls
template<typename T>T GETPARAM();
template<>
int GETPARAM() { return 100 + pos++; }
template<>
double GETPARAM() { return 100.5 + pos++; }
template<>
const char* GETPARAM() { pos++; return "hello"; }
////////////////////////////////////////////////////////////////////////////////
template<class Ret>
struct ArgEvalOrderer {
Ret ret;
template<class... Args>
ArgEvalOrderer(
Ret(*f)(Args...),
Args... args
)
: ret{f(args...)}
{}
operator Ret() const { return ret; }
};
template<class Ret, class... Args>
Ret call_after_ordered_argfetch(Ret(*f)(Args...)) {
// evaluation order guaranteed by braced init list
return ArgEvalOrderer<Ret>{f, GETPARAM<Args>()...};
}
template<class Ret, class... Args>
Ret call_after_ordered_argfetch_buggy(Ret(*f)(Args...)) {
// BUGGY: NO GUARANTEE on evaluation order
return ArgEvalOrderer<Ret>(f, GETPARAM<Args>()...);
}
template<class Ret, class... Args>
Ret call_after_unordered_argfetch(Ret(*f)(Args...)) {
// BUGGY: NO GUARANTEE on evaluation order
return f(GETPARAM<Args>()...);
}
int print7(int a, int b, double c, int d, double e, const char* f, double g) {
std::cout << "print7: " << a
<< ", " << b
<< ", " << c
<< ", " << d
<< ", " << e
<< ", " << f
<< ", " << g
<< std::endl;
return 1;
}
int main() {
call_after_ordered_argfetch(print7);
call_after_ordered_argfetch_buggy(print7);
call_after_unordered_argfetch(print7);
return 0;
}
调用。代理对象可以隐式转换为函数的返回类型。
g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
print7: 100, 101, 102.5, 103, 104.5, hello, 106.5
print7: 113, 112, 111.5, 110, 109.5, hello, 107.5
print7: 120, 119, 118.5, 117, 116.5, hello, 114.5
请注意,较高版本是唯一一个保证有序评估的版本。实际上,I observe (online demo)以下输出:
[HubName("hitCounter")]
public class HitCounterHub : Hub
{
private static int _hitCount = 0;
public void Recordhit()
{
_hitCount += 1;
this.Clients.All.onHitRecorded(_hitCount);
}
}
答案 2 :(得分:0)
这是用于用任意数量的参数静态构建任何函数的代码。它完全独立于任何gcc编译器和std或stl的库(使用的printf
除外,但是您可以安全地删除它们)。但由于可变参数模板,因此需要c++0x。
#include <stdio.h>
// SIZEOF Type Package
template<typename ... Tn>
struct SIZEOF
{ static const unsigned int Result = 0; };
template<typename T1, typename ... Tn>
struct SIZEOF<T1, Tn ...>
{ static const unsigned int Result = sizeof(T1) + SIZEOF<Tn ...>::Result ; };
template<int ...>
struct MetaSequenceOfIntegers { };
template<int AccumulatedSize, typename Tn, int... GeneratedSequence>
struct GeneratorOfIntegerSequence;
template<
int AccumulatedSize,
typename Grouper,
typename Head,
typename... Tail,
int... GeneratedSequence
>
struct GeneratorOfIntegerSequence<
AccumulatedSize, Grouper( Head, Tail... ), GeneratedSequence... >
{
typedef typename GeneratorOfIntegerSequence
<
AccumulatedSize + sizeof(Head),
Grouper( Tail... ),
GeneratedSequence...,
AccumulatedSize
>::type type;
};
template<int AccumulatedSize, typename Grouper, int... GeneratedSequence>
struct GeneratorOfIntegerSequence<AccumulatedSize, Grouper(), GeneratedSequence...>
{
typedef MetaSequenceOfIntegers<GeneratedSequence...> type;
};
template<typename Tn>
class Closure;
template<typename ReturnType, typename... Tn>
class Closure<ReturnType( Tn... )>
{
public:
typedef ReturnType(*Function)(Tn ...);
static const unsigned int PARAMETERS_COUNT = sizeof...( Tn );
static const unsigned int PARAMETERS_LENGTH = SIZEOF<Tn ...>::Result;
private:
Function _entry;
char* _parameters;
public:
Closure(Function _entry, Tn ... an): _entry(_entry)
{
printf( "Closure::Closure(_entry=%d, PARAMETERS_COUNT=%d,
PARAMETERS_LENGTH=%d, sizeof=%d) => %d\n",
&_entry, PARAMETERS_COUNT, PARAMETERS_LENGTH, sizeof(*this), this );
if(PARAMETERS_LENGTH) _parameters = new char[PARAMETERS_LENGTH];
pack_helper( _parameters, an ... );
}
~Closure() {
printf( "Closure::~Closure(this=%d, _entry=%d,
PARAMETERS_COUNT=%d, PARAMETERS_LENGTH=%d, sizeof=%d)\n",
this, &_entry, PARAMETERS_COUNT, PARAMETERS_LENGTH, sizeof(*this) );
if(PARAMETERS_LENGTH) delete _parameters;
}
ReturnType operator()() {
return _run( typename GeneratorOfIntegerSequence< 0, int(Tn...) >::type() );
}
private:
template<int ...Sequence>
ReturnType _run(MetaSequenceOfIntegers<Sequence...>)
{
printf( "Closure::_run(this=%d)\n", this );
return _entry( unpack_helper<Sequence, Tn>()... );
}
template<const int position, typename T>
T unpack_helper()
{
printf( "Closure::unpack_helper(Head=%d, address=%d(%d), position=%d)\n",
sizeof( T ), _parameters + position, _parameters, position );
return *reinterpret_cast<T *>( _parameters + position );
}
public:
template<typename Head, typename ... Tail>
static void pack_helper(char* pointer_address, Head head, Tail ... tail)
{
printf( "Closure::pack_helper(
Head=%d, address=%d)\n", sizeof( Head ), pointer_address );
*reinterpret_cast<Head *>(pointer_address) = head;
pack_helper(pointer_address + sizeof( Head ), tail ...);
}
static void pack_helper(char* pointer_address) {}
};
/**
* Create a closure which can have any return type.
*/
template<typename ReturnType, typename ... Tn>
Closure< ReturnType(Tn ...) > create_closure(
ReturnType(*_entry)( Tn ... ), Tn ... an )
{
auto closure = new Closure< ReturnType(Tn ...) >( _entry, an ... );
printf( "create_closure=%d\n", closure );
return *closure;
}
char test_function1(char arg1, int arg2, bool arg3) {
printf(" test_function1: %c, %d, %d\n", arg1, arg2, arg3);
}
char test_function2(const char* arg1, const char* arg2, char arg3) {
printf(" test_function2: %s, %s, %c\n", arg1, arg2, arg3);
}
char test_function3() {
printf(" test_function3\n");
}
void test_function4() {
printf(" test_function4\n");
}
void test_function5(const char* arg1) {
printf(" test_function5=%s\n", arg1);
}
template<typename ... Tn>
void test_closure(Tn ... an) {
auto closure = create_closure(an ...);
closure();
printf( "\n" );
}
// clang++ -Xclang -ast-print -fsyntax-only test.cpp > expanded.cpp
int main()
{
test_closure( &test_function1, 'a', 10, false );
test_closure( &test_function2, "test1", "test2", 'b' );
test_closure( &test_function3 );
test_closure( &test_function4 );
test_closure( &test_function5, "Testa 3" );
test_closure( &test_function5, "Testa 4" );
}
运行它,您将看到测试结果:
$ g++ -o test test_variadic_critical_section_dynamic.cpp && ./test
Closure::Closure(_entry=-13672,
PARAMETERS_COUNT=3, PARAMETERS_LENGTH=6, sizeof=16) => 164864
Closure::pack_helper(Head=1, address=164976)
Closure::pack_helper(Head=4, address=164977)
Closure::pack_helper(Head=1, address=164981)
create_closure=164864
Closure::_run(this=-13520)
Closure::unpack_helper(Head=1, address=164981(164976), position=5)
Closure::unpack_helper(Head=4, address=164977(164976), position=1)
Closure::unpack_helper(Head=1, address=164976(164976), position=0)
test_function1: a, 10, 0
Closure::~Closure(this=-13520, _entry=-13520,
PARAMETERS_COUNT=3, PARAMETERS_LENGTH=6, sizeof=16)
Closure::Closure(_entry=-13672,
PARAMETERS_COUNT=3, PARAMETERS_LENGTH=17, sizeof=16) => 164976
Closure::pack_helper(Head=8, address=165008)
Closure::pack_helper(Head=8, address=165016)
Closure::pack_helper(Head=1, address=165024)
create_closure=164976
Closure::_run(this=-13520)
Closure::unpack_helper(Head=1, address=165024(165008), position=16)
Closure::unpack_helper(Head=8, address=165016(165008), position=8)
Closure::unpack_helper(Head=8, address=165008(165008), position=0)
test_function2: test1, test2, b
Closure::~Closure(this=-13520, _entry=-13520,
PARAMETERS_COUNT=3, PARAMETERS_LENGTH=17, sizeof=16)
Closure::Closure(_entry=-13624,
PARAMETERS_COUNT=0, PARAMETERS_LENGTH=0, sizeof=16) => 165008
create_closure=165008
Closure::_run(this=-13520)
test_function3
Closure::~Closure(this=-13520, _entry=-13520,
PARAMETERS_COUNT=0, PARAMETERS_LENGTH=0, sizeof=16)
Closure::Closure(_entry=-13624,
PARAMETERS_COUNT=0, PARAMETERS_LENGTH=0, sizeof=16) => 165040
create_closure=165040
Closure::_run(this=-13520)
test_function4
Closure::~Closure(this=-13520, _entry=-13520,
PARAMETERS_COUNT=0, PARAMETERS_LENGTH=0, sizeof=16)
Closure::Closure(_entry=-13624,
PARAMETERS_COUNT=1, PARAMETERS_LENGTH=8, sizeof=16) => 165072
Closure::pack_helper(Head=8, address=609568)
create_closure=165072
Closure::_run(this=-13520)
Closure::unpack_helper(Head=8, address=609568(609568), position=0)
test_function5=Testa 3
Closure::~Closure(this=-13520, _entry=-13520,
PARAMETERS_COUNT=1, PARAMETERS_LENGTH=8, sizeof=16)
Closure::Closure(_entry=-13624,
PARAMETERS_COUNT=1, PARAMETERS_LENGTH=8, sizeof=16) => 609568
Closure::pack_helper(Head=8, address=609600)
create_closure=609568
Closure::_run(this=-13520)
Closure::unpack_helper(Head=8, address=609600(609600), position=0)
test_function5=Testa 4
Closure::~Closure(this=-13520, _entry=-13520,
PARAMETERS_COUNT=1, PARAMETERS_LENGTH=8, sizeof=16)
您可以使用clang++
运行它以查看生成的模板代码:
$ clang++ -Xclang -ast-print -fsyntax-only test.cpp > expanded.cpp
// ...
private:
template<> char _run<<0, 8, 16>>(MetaSequenceOfIntegers<0, 8, 16>)
{
return this->_entry(
this->unpack_helper<0, const char *>(),
this->unpack_helper<8, const char *>(),
this->unpack_helper<16, char>()
);
}
template<> const char *unpack_helper<0, const char *>()
{
return *reinterpret_cast<const char **>(this->_parameters + 0);
}
template<> const char *unpack_helper<8, const char *>() {
return *reinterpret_cast<const char **>(this->_parameters + 8);
}
template<> char unpack_helper<16, char>() {
return *reinterpret_cast<char *>(this->_parameters + 16);
}
// ...
参考