Templated function with optional compile time arg

huangapple go评论66阅读模式
英文:

Templated function with optional compile time arg

问题

以下是翻译好的部分:

我有以下带有可选 port 参数的模板函数,应在编译时识别:

template<typename T>
void inner(T arg1){...}

template<typename T>
void inner(T arg1, int port){...}

我想要从外部函数中以最少的重复调用内部函数:

template<typename T>
void outer(T arg1){
    /* 做一些操作 */
    inner(arg1);
}

template<typename T>
void outer(T arg1, int port){
    /* 做与 void outer(T arg1) 中相同的操作 */
    inner(arg1, port);
}

在我的解决尝试中,我使用了可变参数模板:

template<typename T, typename... Args>
void outer(T arg1, Args... args){
    inner(arg1, args...);
}

它的用法如下:

int main(int argc, char **argv)
{
    outer(10);
    outer(10, 20);
    
	return 0;
}

然而,我不喜欢有可变数量的参数,只想要0个或1个。
要么你指定 port,要么不指定。
我该如何做到这一点?

尝试过探索 SFINAEenable_if 等,但我无法理解它们。

英文:

I have the following templated functions with an optional port argument, which should be recognized at compile time:

template&lt;typename T&gt;
void inner(T arg1){...}

template&lt;typename T&gt;
void inner(T arg1, int port){...}

I want to call the inner functions from outer functions with minimum repetition:

template&lt;typename T&gt;
void outer(T arg1){
    /* Do some stuff */
    inner(arg1);
}

template&lt;typename T&gt;
void outer(T arg1, int port){
    /* Do same stuff as in void outer(T arg1) */
    inner(arg1, port);
}

In my solution attempt I made use of variadic templates:

template&lt;typename T, typename... Args&gt;
void outer(T arg1, Args... args){
    inner(arg1, args...);
}

It is used like this:

int main(int argc, char **argv)
{
    outer(10);
    outer(10, 20);
    
	return 0;
}

However, I do not like to have a variable amount of parameters but just 0 or 1.
Either you specify the port or not.
How can I do this?

Tried to explore SFINAE, enable_if and such, but I was not able to make sense out of it.

答案1

得分: 3

以下是翻译好的部分:

通常避免重复的方式是编写一个函数:

void Do_some_stuff(Some args);

template<typename T>
void outer(T arg1){
    Do_some_stuff( ... );
    inner(arg1);
}

template<typename T>
void outer(T arg1, int port){
    Do_some_stuff( ... );
    inner(arg1, port);
}
英文:

The usual way to avoid repetition is to write a function:

void Do_some_stuff(Some args);

template&lt;typename T&gt;
void outer(T arg1){
    Do_some_stuff( ... );
    inner(arg1);
}

template&lt;typename T&gt;
void outer(T arg1, int port){
    Do_some_stuff( ... );
    inner(arg1, port);
}

答案2

得分: 1

有多种选择可供考虑。最简单的方法是使用可变模板,但在外部函数中限制参数数量,例如使用 static_assert:

#include<iostream>

template<typename T>
void inner(T arg1){std::cout << "one\n";}

template<typename T>
void inner(T arg1, int port){std::cout << "two\n";}

template<typename T, typename... Args>
void outer(T arg1, Args... args){
    static_assert(sizeof...(Args) < 2, "no more than one param");
    inner(arg1, args...);
}

int main()
{
    outer(1,2);
    outer(1);
//    outer(1,2,3); //fails to compile
}

查看代码

如果第二个参数的类型已知,outer 可以是一个单独的函数,接受两个参数,其中一个默认为空的可选项。我无法确定这是否符合您的 API 和 ABI 的要求,但如果可以的话,代码如下:

#include <iostream>
#include <optional>

template<typename T>
void inner(T arg1){std::cout << "one\n";}

template<typename T>
void inner(T arg1, int port){std::cout << "two\n";}

template<typename T>
void outer(T arg1, std::optional<int> port = {} ){
    if (port) {
        inner(arg1, *port);
    } else {
        inner(arg1);
    }
}

int main()
{
    outer(1,2);
    outer(1);
//    outer(1,2,3); //fails to compile
}

查看代码

出于示例的目的,我假设您正在使用 C++17 或更新版本,如果不是,则可以将 std::optional 替换为 Boost 中的版本。

英文:

There are multiple options to consider. The easiest one is using a variadic template but limiting the number of arguments in the outer function, e.g. using static_assert

#include&lt;iostream&gt;

template&lt;typename T&gt;
void inner(T arg1){std::cout &lt;&lt; &quot;one\n&quot;;}

template&lt;typename T&gt;
void inner(T arg1, int port){std::cout &lt;&lt; &quot;two\n&quot;;}

template&lt;typename T, typename... Args&gt;
void outer(T arg1, Args... args){
    static_assert(sizeof...(Args) &lt; 2, &quot;no more than one param&quot;);
    inner(arg1, args...);
}


int main()
{
    outer(1,2);
    outer(1);
//    outer(1,2,3); //fails to compile
}

https://godbolt.org/z/ehcej8zrs

Given the type of the second parameter is known, outer can be a single function taking two parameters, one of which is an optional empty by default. I cannot tell if it's acceptable from your API and ABI's standpoint, if it is though, it looks more-less the following way:

#include &lt;iostream&gt;
#include &lt;optional&gt;

template&lt;typename T&gt;
void inner(T arg1){std::cout &lt;&lt; &quot;one\n&quot;;}

template&lt;typename T&gt;
void inner(T arg1, int port){std::cout &lt;&lt; &quot;two\n&quot;;}

template&lt;typename T&gt;
void outer(T arg1, std::optional&lt;int&gt; port = {} ){
    if (port) {
        inner(arg1, *port);
    } else {
        inner(arg1);
    }
}


int main()
{
    outer(1,2);
    outer(1);
//    outer(1,2,3); //fails to compile
}

https://godbolt.org/z/6jnnMMGKW

For the sake of the example I have assumed you are using C++17 or newer, if not, std::optional can be replaced by the one from Boost.

huangapple
  • 本文由 发表于 2023年5月25日 19:26:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/76331756.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定