我写了一个模板,它接受一个istream&和一个函数,应该从 中提取这个函数的所有参数,istream用这些参数调用函数并返回结果。一切正常,除了函数参数的评估顺序。请参阅下面的代码、更多详细信息和最终问题:
#include <iostream>
#include <vector>
void Foo(int i, std::string s)
{
std::cout << "input was " << i << " and " << s << '\n';
}
template<typename T>
T Parse(std::istream &s)
{
T res;
s >> res;
return res;
}
template<typename TR, typename ... TArgs>
TR Bar(std::istream &s, TR f(TArgs...) )
{
return f(Parse<TArgs>(s)...);
}
int main()
{
Bar(std::cin, Foo);
}
Run Code Online (Sandbox Code Playgroud)
输入:
1 2
Run Code Online (Sandbox Code Playgroud)
预期输出:
input was 1 and 2
Run Code Online (Sandbox Code Playgroud)
实际输出:
input was 2 …Run Code Online (Sandbox Code Playgroud) 在我们的代码库中,我们经常使用std::variant<std::shared_ptr<SomeClass>, ...>。
显然,这需要大量的写作。如何制作模板?
template <class... T>
using VarSP = std::variant<std::shared_ptr<???>>;
Run Code Online (Sandbox Code Playgroud)
T以上代码片段应该放在哪里?所需的行为应为:
VarSP<Foo, Bar, Baz> // std::variant<std::shared_ptr<Foo>, std::shared_ptr<Bar>, std::shared_ptr<Baz>>
Run Code Online (Sandbox Code Playgroud) 为了扩展灵活的函数参数,有一种方法使用std::initializer_list. 然而我无法理解。任何人都可以以可以理解的方式解释这一点吗?
template<typename T, typename... Args>
auto print(T value, Args... args) {
std::cout << value << std::endl;
return std::initializer_list<T>{([&] {
std::cout << args << std::endl;
}(), value)...};
}
Run Code Online (Sandbox Code Playgroud) 当我使用参数包时,我注意到这样一种情况(如下所示)在 gcc 和 clang 中编译得很好,但在 msvc 中却不行:
template<class T> void func(T a, T b= T{})
{
}
template<class T, class... S> void func(T a, S... b)
{
}
int main()
{
func(1); // Should this call succeed?
}
Run Code Online (Sandbox Code Playgroud)
这是验证相同内容的链接:https://godbolt.org/z/8KsrcnMez
可以看到,上面的程序在 msvc 中失败,并显示错误消息:
<source>(13): error C2668: 'func': ambiguous call to overloaded function
<source>(6): note: could be 'void func<int,>(T)'
with
[
T=int
]
<source>(2): note: or 'void func<int>(T,T)'
with
[
T=int
]
<source>(13): note: while trying to match the argument list …Run Code Online (Sandbox Code Playgroud) c++ language-lawyer function-templates pack-expansion parameter-pack
目前这是伪代码,因为这是我在开始将其编写为完整代码之前正在研究的想法。
我知道我可以创建一个正常的可变参数函数使用va_arg和va_list如printf()确实,但是,我想完全避免使用它们。
我正在考虑使用模板可变参数来代替。我正在考虑使用可变参数制作一个可实例化的类模板。这里的条件是这个类的构造函数只能接受两种类型,但两种类型的数量可以不同。我知道,与编译器的解释方式和调用顺序相比,代码中参数的写入位置是不可知的,但这不是问题。我为参数选择的顺序是出于可读性和一致性目的的约定。
这是伪代码的示例:
class TypeIn {...}
class TypeOut{...}
template<typename... T1, typename... T2>
class MyObject {
std::array<TypeIn*> inputs_;
std::array<TypeOut*> outputs_;
public:
MyObject(T1&&... inputs, T2&& ... outputs) { ... }
};
Run Code Online (Sandbox Code Playgroud)
因为我仍然在C ++ 17的工作,并没有C ++ 20的概念,模块和协程,只是还没有,这将是最干净最可靠和最有效的方式,以确保T1是TypeIn和T2是一TypeOut类对象并相应地填充数组?我可以使用向量,但是一旦对象被构造,输入和输出的大小就不会改变。
可能的用例是:
using In = TypeIn;
using Out = TypeOut;
MyObject obj( In a, In b, In c, Out x, Out y);
Run Code Online (Sandbox Code Playgroud)
如果可能的话,我宁愿不使用这个语法:
MyObject<In,In,In,Out,Out> obj( In a, In b, In c, Out …Run Code Online (Sandbox Code Playgroud)