I have a variadic template function f. This compiles fine (using g++ -std=c++11 and possibly using c++0x):
#include <tuple>
template<int ...>
struct seq { };
template <typename ...T, int ...S>
void f(std::tuple<T...> arg, seq<S...> s) {
// ... do stuff
}
int main() {
f<int>(std::tuple<int>(10), seq<0>());
return 0;
}
The compiler automatically fills in the int ...S that works.
However, I can't seem to manually provide the integer arguments:
int main() {
f<int, 0>(std::tuple<int>(10), seq<0>());
return 0;
}
Output:
/tmp/t.cpp: In function ‘int main()’: /tmp/t.cpp:12:42: error: no
matching function for call to ‘f(std::tuple, seq<0>)’
/tmp/t.cpp:12:42: note: candidate is: /tmp/t.cpp:7:6: note:
template void f(std::tuple<_TElements ...>,
seq) /tmp/t.cpp:7:6: note: template argument
deduction/substitution failed:
I believe I've read that technically there should only be one variadic template parameter pack provided to a template function (and in the first case, it is completely determined by context), so that explains it(?).
For debugging, is there a way in GCC to output the expansion used for ...S to stderr or stdout? It would be very useful for debugging things like this when they don't compile at first.
I know no way to specify two template argument packs manually. Since a template pack may contain arbitrarily many arguments, there is no way for the compiler to know when you meant the first one to stop and the second one to start. Automatic or partially automatic deduction seems to work, though, but I am not sure if this is just some generousity of g++...
I am not sure what you are actually trying to do, but I bet that you do not need both template packs at the same time. You might introduce one layer of indirection, e.g.,
template <typename ... Tuple_Elements>
void do_something_with_single_value(std::tuple<Tuple_Elements...> arg, int s) {
// ... do stuff
}
template <typename Tuple_Type, int ...S>
void f(Tuple_Type arg, seq<S...> s) {
// ... do stuff which needs all S at the same time
// ... call do_something_with_single_value in compile time loop to access tuple elements
}
Perhaps your signature is a hint that your function has too many responsibilities. Try to create smaller functions with clear responsibilities.
There is a way to output the arguments deduced for T and S, but only if the compiler can determine a match. For this, you would need to provoke an error at compile time:
template <typename ...T, int ...S>
void f(std::tuple<T...> arg, seq<S...> s) {
static_assert(std::tuple_size<std::tuple<T...>>::value < 0, "Provoked error message");
// ... do stuff
}
This would generate the following output in your working example:
stack.cpp: In function ‘void f(std::tuple<_Elements ...>, seq<S ...>) [with T = {int}, int ...S = {0}]’:
stack.cpp:15:34: instantiated from here
stack.cpp:10:2: error: static assertion failed: "Provoked error message"
For getting stderr for types and values in situations like this I, personally, find it best to force a compile error for the situation you're interested in.
So in this situation we want to know exactly what the type and integer packs for the first example where it compiles correctly. If we cause a compile fail before instantiation of the function then the compile error will refer to the function without the info we want:
template <class ... T, int ... S>
void f (std::tuple<T...> arg, seq<S...> s)
{
foo
}
In function 'void f(std::tuple<_Elements ...>, seq<S ...>)':
error: 'foo' was not declared in this scope
demo
So now let's fail compilation during instantiation. This means that we'll have to write something that could make sense for some types of T..., but not for our instantiation. I usually write a function like force_fail to make this easy to repeat:
template <class T, class ...>
int force_compile_fail ()
{
return T::force_compile_fail;
}
template <class ... T, int ... S>
void f (std::tuple<T...> arg, seq<S...> s)
{
force_compile_fail<T...>();
}
In instantiation of 'int force_compile_fail() [with T = int;
= {}]':
required from 'void f(std::tuple<_Elements ...>, seq<S ...>) [with T = {int}; int ...S = {0}]'
required from here
error: 'force_compile_fail' is not a member of 'int'
return T::force_compile_fail;
demo
Related
In order to circumvent the restriction on partially supplied explicit template arguments, I embed the struct from which I want to deduce the class template parameters (Internal) into a second struct (Container).
I would like to enable the user of the code to create e.g. shared pointers of the resulting type. By writing my own create function within the struct, this works just fine.
#include <memory>
/// Container that is used in order to partially specify template arguments
template <int A> struct Container {
/// Contained type, of which the template arguments are deduced.
template <int B> struct Internal {
explicit Internal(std::integral_constant<int, B> fu) { (void)fu; }
};
/// Helper function
template <int C>
[[nodiscard]] static auto create(std::integral_constant<int, C> t) noexcept {
return std::make_shared<Container<A>::Internal<C>>(t);
}
};
int main() {
Container<1>::Internal works{std::integral_constant<int, 8>{}};
auto const worksAswell = Container<1>::create(std::integral_constant<int, 8>{});
}
But when I try to use make_shared directly, it fails. I would like to enable the user to use e.g. the std::make_shared function.
int main() {
auto const fails = std::make_shared<Container<1>::Internal>(std::integral_constant<int, 8>{});
}
From what I understand, this fails because I cannot partially specify template arguments, and I am unable to deduce them from the make_shared function if I don't want to specify all template parameters.
main.cc: In function ‘int main()’:
main.cc:21:74: error: no matching function for call to ‘make_shared<1>(std::integral_constant<int, 8>)’
21 | auto const fails = std::make_shared<1>(std::integral_constant<int, 8>{});
| ^
In file included from /usr/include/c++/9.2.0/memory:81,
from /home/juli/main9.cc:1:
/usr/include/c++/9.2.0/bits/shared_ptr.h:714:5: note: candidate: ‘template<class _Tp, class ... _Args> std::shared_ptr<_Tp> std::make_shared(_Args&& ...)’
714 | make_shared(_Args&&... __args)
| ^~~~~~~~~~~
/usr/include/c++/9.2.0/bits/shared_ptr.h:714:5: note: template argument deduction/substitution failed:
Is it possible to enable generator functions like std::make_shared to partially deduce template arguments like that? The entire code can be found here.
If you create your own make_shared that accepts a template template parameter we can use decltype to deduce the resulting type and pass that on to std::make_shared.
#include <memory>
#include <type_traits>
/// Container that is used in order to partially specify template arguments
template <int A> struct Container {
/// Contained type, of which the template arguments are deduced.
template <int B> struct Internal {
explicit Internal(std::integral_constant<int, B> fu) { (void)fu; }
};
};
template <template <int> typename partial, typename... Args>
auto make_shared(Args&&... args) {
using target_type = std::remove_pointer_t<decltype(new partial{std::declval<Args>()...})>;
return std::make_shared<target_type>(std::forward<Args>(args)...);
}
using std::make_shared;
int main() {
auto const fails = make_shared<Container<1>::Internal>(std::integral_constant<int, 8>{});
static_assert(std::is_same_v<const std::shared_ptr<Container<1>::Internal<8>>, decltype(fails)>);
}
The only issue here is that our make_shared needs to know the template signature of the expected target.
On the positive side we can add several overloads for different template signatures and we can use one parameter pack.
I am trying to write a function which takes another function, using parameter packs and some standard matching rules. As an example:
template <typename... TListElems, typename... TVectorElems>
void goal(void (*fn)(std::list<TListElems>..., std::vector<TVectorElems>...));
In order to disambiguate TListElems and TVectorElems, I added some std::tuple<T...>* so a caller can be explicit:
template <typename... TListElems, typename... TVectorElems>
void foo(std::tuple<TListElems...>*,
std::tuple<TVectorElems...>*,
void (*)(std::list<TListElems>..., std::vector<TVectorElems>...))
{
// blah blah blah
}
void bar(std::list<int>, std::list<unsigned>, std::vector<float>, std::vector<double>)
{
// blah blah blah
}
int main()
{
foo((std::tuple<int, unsigned>*) nullptr,
(std::tuple<float, double>*) nullptr,
&bar);
}
Clang happily compiles this in the way I would expect, while g++ (7.2.1) gives the compilation error:
matching.cpp: In function ‘int main()’:
matching.cpp:20:13: error: no matching function for call to ‘foo(std::tuple<int, unsigned int>*, std::tuple<float, double>*, void (*)(std::list<int>, std::list<unsigned int>, std::vector<float>, std::vector<double>))’
&bar);
^
matching.cpp:6:6: note: candidate: template<class ... TListElems, class ... TVectorElems> void foo(std::tuple<_Tps ...>*, std::tuple<_Elements ...>*, void (*)(std::list<TListElems>..., std::vector<TVectorElems>...))
void foo(std::tuple<TListElems...>*,
^~~
matching.cpp:6:6: note: template argument deduction/substitution failed:
matching.cpp:20:13: note: mismatched types ‘std::vector<TVectorElems>’ and ‘std::list<int>’
&bar);
^
In main, I would expect the call to foo to deduce TListElems as <int, unsigned> and TVectorElems as <float, double>, leading fn to be of type void (*)(std::list<int>, std::list<unsigned>, std::vector<float>, std::vector<double>) (the way things operate when there is only one pack or if I had manually written the overload).
§14.8.2.5/10 is the closest the Standard comes to explicitly preventing the foo example from working:
[Note: A function parameter pack can only occur at the end of a parameter-declaration-list (8.3.5). -end note]
The std::list<TListElems>... bit of fn seems like it would violate this note, but that's not entirely clear.
The question is: Who is right? GCC, Clang, or something else?
I think clang is right here.
In void (*)(std::list<TListElems>..., std::vector<TVectorElems>...), TListElems... is a non-deduced context, which makes TVectorElems... also a non-deduced context. But both parameter packs are deducible from the two tuple pointer arguments, and it's expected to be able to just use that deduction result here too.
I filed gcc bug 83542.
You may make happy both compilers with non deducible type:
template <typename T>
struct non_deducible {
using type = T;
};
template <typename T> using non_deducible_t = typename non_deducible<T>::type;
template <typename... TListElems, typename... TVectorElems>
void foo(std::tuple<TListElems...>*,
std::tuple<TVectorElems...>*,
void (*)(non_deducible_t<std::list<TListElems>>...,
non_deducible_t<std::vector<TVectorElems>>...))
{
// blah blah blah
}
Demo
For a generic library I'm trying to define a concept in terms of having a correct implementation of a traits struct. In particular I want to check that the user has provided all required nested types, static member functions and data members. However, I can't find a way to require a nested templated type(-alias).
I have a declaration of the traits struct
template <typename>
struct trait;
and a specialization for chars
template <>
struct trait<char> {
template <typename>
using type = int;
};
I now define my concept in terms of this trait
template <typename T>
concept bool SatisfiesTrait = requires() {
typename trait<T>; // require the user to have spcialized
// for their type
typename trait<T>::type<long long>; // require the nested template
};
as well as a function requiring a type satisfying this concept
constexpr bool foo(SatisfiesTrait) { return true; }
In my main method I then try to call this function with a char:
int main() {
foo('c');
}
When compiling all this with GCC I get the error message
prog.cc:15:24: error: 'trait<T>::type' is not a type
typename trait<T>::type<long long>;
^~~~
prog.cc: In function 'int main()':
prog.cc:26:11: error: cannot call function 'constexpr bool foo(auto:1) [with auto:1 = char]'
foo('c');
^
prog.cc:18:16: note: constraints not satisfied
constexpr bool foo(SatisfiesTrait) {
^~~
prog.cc:18:16: note: in the expansion of concept 'SatisfiesTrait<auto:1>' template<class T> concept const bool SatisfiesTrait<T> [with T = char]
However, when I change my main function to
int main() {
typename trait<char>::type<long long> v;
(void) v;
foo('c');
}
and comment out the requirement of the nested alias template it compiles just fine. The same problem occurs when the nested type has a non-type template parameter instead of a type parameter.
Am I doing something wrong here or is this a bug in GCCs implementation of the Concepts TS?
The code can also be found on Wandbox.
ideone example
I need to forward some predefined arguments plus some user-passed arguments to a member function.
#define FWD(xs) ::std::forward<decltype(xs)>(xs)
template<class T, class... Ts, class... TArgs>
void forwarder(void(T::*fptr)(Ts...), TArgs&&... xs)
{
T instance;
(instance.*fptr)(FWD(xs)..., 0);
// ^
// example predefined argument
}
forwarder(&example::f0, 10, 'a');
forwarder(&example::f1, 10, "hello", 5);
This works properly for non-template member functions.
The member function pointer passed to forwarder can, however, point to template functions as well. Unfortunately, the compiler is not able to deduce the type of T in that case:
struct example
{
void f0(int, int) { }
template<class T>
void f1(T&&, int) { }
};
// Compiles
forwarder(&example::f0, 10);
// Does not compile
forwarder(&example::f1, 10);
Errors:
prog.cpp:30:28: error: no matching function for call to 'forwarder(<unresolved overloaded function type>, int)'
forwarder(&example::f1, 10);
^
prog.cpp:20:6: note: candidate: template<class T, class ... Ts, class ... TArgs> void forwarder(void (T::*)(Ts ...), TArgs&& ...)
void forwarder(void(T::*fptr)(Ts...), TArgs&&... xs)
^
prog.cpp:20:6: note: template argument deduction/substitution failed:
prog.cpp:30:28: note: couldn't deduce template parameter 'T'
forwarder(&example::f1, 10);
Is there any way I can help the compiler deduce the correct types without changing the interface of forwarder?
If not, what's the best way of solving this issue without making the user syntax too convoluted?
EDIT: It would also be acceptable to pass the member function pointer as a template parameter, maybe through a wrapper. The target member function will always be known at compile-time. Pseudocode:
forwarder<WRAP<example::f0>>(10, 'a');
// Where WRAP can be a macro or a type alias.
ideone example
I compiled your code in gcc 4.9 by providing template arguments to the member function pointer;
like this
int main(){
// Compiles
forwarder(&example::f0, 10);
//Does not compile
forwarder(&example::f1, 10);
//Does compile, instantiate template with int or what ever you need
forwarder(&example::f1<int>,10)
}
I believe what is going on is that you need to instantiate the template member function.
does that change your interface too much?
I think any answer will revolve around instantiating that member template somehow.
Normally, to test a if a pointer points to function, use std::is_function is enough.
However, it cannot work with lambda. Since lambda is an object with operator().
Now I have to use both is_function and is_object to check if one works like function, as below:
std::is_function<decltype(f)>::value || std::is_object<decltype(f)>::value
So I'm wondering if there is a better way to test if one is lambda or not?
EDIT:
Related code:
template<typename Func>
void deferJob(Func f, int ms=2000)
{
if(! std::is_function<decltype(f)>::value
&& ! std::is_object<decltype(f)>::value){
qDebug()<<"Not function!";
return;
}
QTimer* t = new QTimer;
t->setSingleShot(true);
QObject::connect(t, &QTimer::timeout,
[&f, t](){
qDebug()<<"deferJob";
f();
t->deleteLater();
});
t->start(ms);
}
EDIT2:
Similar question: C++ metafunction to determine whether a type is callable
So here are some thoughts that may or may not be helpful.
To create a type_trait that works for functors, lambdas and traditional functions, I think I would look into seeing if the template argument is convertible into a std::function<void()>. I think that would cover most bases in a clear way.
As we've mentioned in the comments, you can't test a template argument like the way you are doing. The f() later in the function will cause a compile error, and so you'll never have the opportunity to see the runtime error.
You can try to do something with std::enable_if. You'd need to create template specializations so that SFINAE can function to choose the correct implementation. This would use that type_trait that I mentioned in bullet 1.
If you did this, you could make the implementation of the other template to be a static_assert to create a "better" error message.
That being said, the compiler error messages aren't that bad in the first place. (At least in clang and gcc. I haven't looked as msvc).
This doesn't get you a great error message, but it does get you a different one:
#include <cassert>
#include <functional>
#include <type_traits>
template <typename Func>
typename std::enable_if<std::is_convertible<Func, std::function<void()>>::value>::type
deferJob(Func f, int ms=2000) {
}
void normal_function() {}
int main() {
deferJob([]() {}); // works
deferJob(&normal_function); // works
deferJob(3); // compile time error
}
In Clang, I get an error that looks like:
foo.cc:15:2: error: no matching function for call to 'deferJob'
deferJob(3); // compile time error
^~~~~~~~
foo.cc:6:25: note: candidate template ignored: disabled by 'enable_if' [with Func = int]
typename std::enable_if<std::is_convertible<Func, std::function<void()>>::value>::type
In GCC, I get an error that looks like:
foo.cc: In function ‘int main()’:
foo.cc:15:12: error: no matching function for call to ‘deferJob(int)’
deferJob(3); // compile time error
^
foo.cc:15:12: note: candidate is:
foo.cc:7:1: note: template<class Func> typename std::enable_if<std::is_convertible<Func, std::function<void()> >::value>::type deferJob(Func, int)
deferJob(Func f, int ms=2000) {
^
foo.cc:7:1: note: template argument deduction/substitution failed:
foo.cc: In substitution of ‘template<class Func> typename std::enable_if<std::is_convertible<Func, std::function<void()> >::value>::type deferJob(Func, int) [with Func = int]’:
foo.cc:15:12: required from here
foo.cc:7:1: error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
We could go one step further (although doing it this way makes it hard to extend further) and add an additional function:
template <typename Func>
typename std::enable_if<not std::is_convertible<Func, std::function<void()>>::value>::type
deferJob(Func f, int ms=2000) {
static_assert(false, "You should pass a function");
}
This causes clang to report (at compile time):
foo.cc: In function ‘typename std::enable_if<(! std::is_convertible<Func, std::function<void()> >::value)>::type deferJob(Func, int)’:
foo.cc:14:2: error: static assertion failed: You should pass a function
static_assert(false, "You should pass a function");
But sadly, it doesn't give a stack trace, so I would find this far less helpful than any of the earlier messages.
And finally, we could also replace that static assert with your runtime message:
template <typename Func>
typename std::enable_if<not std::is_convertible<Func, std::function<void()>>::value>::type
deferJob(Func f, int ms=2000) {
qDebug() << "Not function!";
}