admin管理员组文章数量:1277910
I would appreciate if someone is able to supply me with better terminology for the question as I am struggling to put it into words in the title. Essentially, my problem is I require a struct along the lines of
template <typename... Types>
struct acceptor {
// ...
template <
// assumedly, something needs to go here
>
static inline void accept(void) {
// ...
}
// ...
};
such that I am able to run
int main(void) {
acceptor<int, int, float>::template accept<0, 1, 0.5f>();
acceptor<unsigned long, double>::template accept<6UL, -4.6>();
return 0;
}
Can I please get a definitive answer on whether or not this is possible within the C++ language and if so, how?
I tried
template <
Types... Values
>
static inline void accept(void) {
// ...
}
but that just seemingly tried to make essentially a variadic of the first type rather than a single non-type parameter per outer argument. The argument appears to always be wrong number of template arguments (<whatever number of arguments I specified>, should be 1)
.
It does not appear to be possible in C++20 or any later version from what I can tell and I've had to construct a structural (so it can be used at compile time) tuple type to handle this but it is somewhat ugly and I'd like to avoid using it if possible. Noting that this was being done on an Ubuntu install of gcc
.
I would appreciate if someone is able to supply me with better terminology for the question as I am struggling to put it into words in the title. Essentially, my problem is I require a struct along the lines of
template <typename... Types>
struct acceptor {
// ...
template <
// assumedly, something needs to go here
>
static inline void accept(void) {
// ...
}
// ...
};
such that I am able to run
int main(void) {
acceptor<int, int, float>::template accept<0, 1, 0.5f>();
acceptor<unsigned long, double>::template accept<6UL, -4.6>();
return 0;
}
Can I please get a definitive answer on whether or not this is possible within the C++ language and if so, how?
I tried
template <
Types... Values
>
static inline void accept(void) {
// ...
}
but that just seemingly tried to make essentially a variadic of the first type rather than a single non-type parameter per outer argument. The argument appears to always be wrong number of template arguments (<whatever number of arguments I specified>, should be 1)
.
It does not appear to be possible in C++20 or any later version from what I can tell and I've had to construct a structural (so it can be used at compile time) tuple type to handle this but it is somewhat ugly and I'd like to avoid using it if possible. Noting that this was being done on an Ubuntu install of gcc
.
3 Answers
Reset to default 9There seems to be a bug in gcc and MSVC preventing the instantiation of accept
using Types... values
, but you can work around it by using auto...
:
#include <type_traits>
template <class... Types>
struct acceptor {
template <auto... values>
// ^^^^^^^
requires std::conjunction_v<std::is_same<Types, decltype(values)>...>
static void accept() {
// use values as you want:
(..., (std::cout << ' ' << values));
std::cout << '\n';
}
};
requires std::conjunction_v<std::is_same<Types, decltype(values)>...>
is there to constrain the accepted non-type template parameters to what you supplied in Types
.
Demo
Clang accepts
template <class... Types>
struct acceptor {
template <Types... values>
static void accept() { /* .. */ }
};
Demo but reject by gcc/msvc :-(
And all accept a "generic" version with requires
:
template <class... Types>
struct acceptor {
template <auto... values>
requires((std::is_same_v<decltype(values), Types> && ...))
static void accept() { /* .. */ }
};
Demo
In conjunction with the similar answers provided by @TedLyngmo (https://stackoverflow/a/79464046/28414083) and @Jarod42 (https://stackoverflow/a/79464150/28414083), the accepted form of solution for the specific question asked would be:
#include <type_traits>
template <class... Types>
struct acceptor {
template <auto... Values>
requires std::conjunction_v<std::is_same<Types, decltype(Values)>...>
static inline void accept(void) {
// ...
}
};
as this compiles in GCC. Unfortunately, this obviously destroys an IDE's ability to use any kind of "intellisense". It also requires you to specify the values, even as literals, in their specific types, meaning that the literal 1
, for example, would not work for an input of a long
's corresponding template non-type parameter as the 1
literal is considered an int
by the compiler. This could be beaten by changing std::is_same
to std::is_trivially_constructible
in the requirement clause or similar but it's recommended, where possible, to change to something like:
#include <type_traits>
template <class... Types>
struct acceptor {
template <Types... Values>
struct internal {
static inline void accept(void) {
// ...
}
};
};
which has an internal temploid struct that, unlike its internal temploid function counterpart, is able to compile with that template in GCC. This changes the format of the expected use to:
int main(void) {
// allows '1U' specified for 'int'
acceptor<signed char, int, float>::template internal<0, 1U, 0.5f>::accept();
// allows '6' specified for 'unsigned long'
acceptor<unsigned long, double>::template internal<6, -4.6>::accept();
return 0;
}
Tested with gcc
version: Ubuntu 13.2.0-4ubuntu3.
本文标签: Interpreting C variadic template arguments from other variadic template argumentsStack Overflow
版权声明:本文标题:Interpreting C++ variadic template arguments from other variadic template arguments - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741259950a2367423.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
_Types
used for? Note that it's a reserved name and you shouldn't use those andvoid main(void)
should beint main()
. – Ted Lyngmo Commented Feb 24 at 15:11void main(void)
is incorrect C++ code.main
always returns anint
. – NathanOliver Commented Feb 24 at 15:27