У меня есть шаблон класса, который выглядит так:
template<typename... Args>
class Foo
{
public:
void Bar() {
(std::get<Args>(m_args).Bar(), ...);
}
private:
std::tuple<Args...> m_args;
};
И вот как я его использую:
template<size_t I>
class Test
{
public:
void Bar() {
std::cout << I << std::endl;
}
};
int main() {
Foo<Test<0>, Test<1>> object;
object.Bar();
}
Эта версия прекрасно работает, но мне нужно переместить определение метода из интерфейса класса (чтобы повысить его читабельность). Вопрос в том, что синтаксис, чтобы сделать этот трюк?
Я пробовал это:
template<typename... Args>
void Foo<Args...>::Bar() {
(std::get<Args>(m_args).Bar(), ...);
}
но компиляция завершается с сообщением об ошибке:
error C3520: 'Args': parameter pack must be expanded in this context
note: while compiling class template member function 'void Foo<Test<0>,Test<1>>::Bar(void)'
note: see reference to function template instantiation 'void Foo<Test<0>,Test<1>>::Bar(void)' being compiled
note: see reference to class template instantiation 'Foo<Test<0>,Test<1>>' being compiled
error C2228: left of '.Bar' must have class/struct/union
error C2059: syntax error: '...'
Я проверил этот код на Clang 7, и он работает так, что он выглядит как ошибка компилятора MSC (Visual Studio 15.7.1).
Эта вещь выглядит как ошибка MSVC и воспроизводится при использовании выражений сворачивания.
Таким образом, обходной путь — это понижение кода с C ++ 17 до C ++ 14 и использование «классического» initializer_list
взломать:
template<typename... Args>
void Foo<Args...>::Bar() {
(void)std::initializer_list<int>{
(std::get<Args>(m_args).Bar(), 0)...
};
}
Других решений пока нет …