i want to forward a variadic template pack and another template pack like this:
template<class t, class... targs, class... args_t>
t create(argst_t&&... args)
{
return t<targs...>(std::forward<args_t>(args)...);
}
t is not a templated class, only the constructor is templated.
it is supposed to be called like this:
class a{
public:
template<class... args_t>
a(args_t... args) {}
};
int main()
{
create<a, int, float>(10, 5.5);
}
this should call a::awith the arguments 10 as an integer an 5.5 as a float.
is this possible and if how?
I have a template class that should have a friend: a make_object function that allows to deduct certain types and values. I wish to make friends only those instantiations that match the types of the template class. The simplified version of my code is below:
template<size_t S, typename T>
class Object {
private:
Object(T t);
template<typename U, typename... Args>
friend auto make_object(U, Args... args);
};
template<typename U, typename... Args>
inline auto make_object(U u, Args... args)
{
constexpr size_t S = sizeof...(Args);
return std::unique_ptr<Object<S, U>>(new Object<S, U>(u));
}
Taking this code as an example I wish to make friends only those instantiations of make_object whose typename U matches the typename T of the object. Is that even possible?
If your requirement is simply befriending a function template with the same template parameter as T, then this would be sufficient:
#include <cstdint>
template <typename T, typename ... TArgs>
auto make_object(T, TArgs...);
template<std::size_t size, typename T>
class Object {
private:
Object(T t);
friend auto make_object<T>(T);
};
template <typename T, typename ... TArgs>
auto make_object(T t, TArgs... args) {
Object<0u, T>{t}; // Compiles
}
template <>
auto make_object<float>(float f) {
// Error: Constructor is private
Object<0u, int>{static_cast<int>(f)};
}
Compiler Explorer
You can use a class to separate the U parameter of make_object (which has to match with the T of Object) from the Args parameter pack, which does not have to match. Then, befriend the helper class, giving all instantiations of your function access to the private members of Object.
template<typename U>
struct make_object_t;
template<std::size_t S, typename T>
class Object {
private:
Object(T t);
friend class make_object_t<T>;
};
template<typename U>
struct make_object_t {
template<typename... Args>
static auto make_object(U u, Args... args) {
constexpr std::size_t S = sizeof...(Args);
return std::unique_ptr<Object<S, U>>(new Object<S, U>(u));
}
};
Finally, write a helper function to hide the class from the API:
template<typename U, typename... Args>
auto make_object(U&& u, Args&&... args) {
return make_object_t<U>::template make_object<Args...>(std::forward<U>(u), std::forward<Args>(args)...);
}
Now, e.g. this works
int main() {
std::unique_ptr<Object<3, int>> ptr = make_object(5, 'a', 0x0B, "c");
}
But, e.g. make_object_t<char> cannot use Object<S, int>::Object:
template<>
struct make_object_t<char> {
template<typename... Args>
static auto make_object(char u, Args... args) {
constexpr std::size_t S = sizeof...(Args);
return std::unique_ptr<Object<S, int>>(new Object<S, int>(u));
}
};
int main() {
// error here from instantiation of above function template
auto oops = make_object('n', 'o');
}
If you want to have a friend template, you can make all the instatiations of the template a friend, like in your example, or you can make a full specialization a friend.
There is nothing in between unfortunately.
To work around that you could wrap your make_object function in a template class and make that template class a friend.
#include <type_traits>
#include <iostream>
#include <memory>
template<typename U>
struct object_maker;
template<std::size_t S, typename T>
class Object {
private:
Object(T) {}
friend struct object_maker<T>;
};
template<typename U>
struct object_maker
{
template<typename... Args>
static auto make_object(U u, Args... args)
{
constexpr std::size_t S = sizeof...(Args);
return std::unique_ptr<Object<S, U>>(new Object<S, U>(u));
}
};
int main()
{
auto obj = object_maker<int>::make_object(7);
static_assert(std::is_same_v<decltype(obj), std::unique_ptr<Object<0,int>>>);
}
As far as I understand, make_object() is a convenience function template that takes advantage of template argument deduction for creating Object objects.
You can create an additional function template, e.g., create_object(), that corresponds to the same template parameters as the Object class template: size_t and a type template parameter. Then, you can easily grant friendship in Object to an instance of this function template that has the same template arguments as Object:
template<size_t, typename>
class Object;
template<size_t S, typename T>
inline auto create_object(T t) {
return std::unique_ptr<Object<S, T>>(new Object<S, T>(t));
}
template<size_t S, typename T>
class Object {
private:
Object(T t);
friend auto create_object<S, T>(T);
};
Your original make_object() function template just delegates to this new function template, create_object():
template<typename U, typename... Args>
inline auto make_object(U u, Args... args)
{
constexpr size_t S = sizeof...(Args);
return create_object<S, U>(std::move(u));
}
Once you know the number of elements in the parameter pack Args, you don't need the parameter pack any longer. You only pass the deduced U and the calculated S as template arguments to create_object().
when attempting to get functions' signatures when they are input into templates its fairly easy, just do the following:
template <class OutType, class... ArgTypes>
void foo(OutType (*func)(ArgTypes...));
it is only marginally more complicated to get a non-static member function:
template <class OutType, class MemberOf, class... ArgTypes>
void foo(OutType (MemberOf::*func)(ArgTypes...));
// or
template <class OutType, class MemberOf, class... ArgTypes>
void foo(OutType (MemberOf::*func)(ArgTypes...) const);
but how exactly do you combine the two function declarations above into one when it doesn't matter whether or not the input method is const?
Unfortunately, the presence or absence of const on a non-static member function is not a feature that can be deduced separately from the function type it appertains to. Therefore, if you want to write a single foo template declaration that is limited to accepting pointers to members (but accepts both const and non-const member functions) then it would have to be:
template <class MemberOf, class F>
void foo(F MemberOf::*func);
For example:
#include <type_traits>
template <class MemberOf, class F>
void foo(F MemberOf::*func) {
static_assert(std::is_same<F, void(int) const>::value);
}
struct S {
void bar(int) const {}
};
int main() {
foo(&S::bar);
}
You cannot have F's argument types deduced at that point. You would have to dispatch to a helper function. (But we cannot deduce all the types at once while also writing a single declaration that accepts both const and non-const. If that's the only thing you'll accept, then sorry, it's not possible.) We can do this like so:
template <class T>
struct remove_mf_const;
template <class R, class... Args>
struct remove_mf_const<R(Args...)> {
using type = R(Args...);
};
template <class R, class... Args>
struct remove_mf_const<R(Args...) const> {
using type = R(Args...);
};
template <bool is_const, class F, class OutType, class MemberOf, class... ArgTypes>
void foo_helper(F func, OutType (MemberOf::*)(ArgTypes...)) {
// now you have all the types you need
}
template <class MemberOf, class F>
void foo(F MemberOf::*func) {
static_assert(std::is_function<F>::value, "func must be a pointer to member function");
using NonConstF = typename remove_mf_const<F>::type;
constexpr bool is_const = !std::is_same<F, NonConstF>::value;
foo_helper<is_const>(func, (NonConstF MemberOf::*)nullptr);
}
Coliru link
I am writing Monitor class for synchronization problem and I would like to implement an 'Entry' class that will wrap a std::function.
I implemented it a bit, used function traits, but right now I am only able to construct Entry objects using prepared std::function object. Attempts to write a constructor that has an plain function as a parameter failed with compiler messages about template argument deduction/substitution and <anonymous> parameter.
The program is working but I am just curious how to implement given constructor, this is my code:
template <class F>
struct FunctionType;
template <class R, class Object, class... Args>
struct FunctionType<R (Object::*)(Args...)> {
typedef R return_type;
};
template <class R, class Object, class... Args>
struct FunctionType<R (Object::*)(Args...) const> {
typedef R return_type;
};
template <class F> class Entry {
std::function<F> internalFunction;
...
public:
template <F> Entry(const F& function){
// It doesn't work.
}
template <F> Entry(const std::function<F> function) :
internalFunction(function) {
}
template<F, class... Arguments>
typename FunctionType<F>::return_type operator()(Arguments... arguments){
return internalFunction(arguments...);
}
};
A couple of things:
template<F>
doesn't make any sense at all. You get the type of F from the template parameter on the class, use that and remove this altogether.
Next, it's probably easier for you to use a trailing return type on your operator() function:
template<class... Arguments>
auto operator()(Arguments... arguments) -> decltype(internalFunction(arguments...))
{
return internalFunction(arguments...);
}
(If you have C++14 you can just use auto).
Live Demo
Here's your fixed class
template <class F> class Entry {
std::function<F> internalFunction;
public:
Entry(const F& function){
// It doesn't work.
}
Entry(const std::function<F> function) :
internalFunction(function) {
}
template<class... Arguments>
auto operator()(Arguments... arguments) -> decltype(internalFunction(arguments...)){
return internalFunction(arguments...);
}
};
Suppose we have the general function pointer:
template <class ArgT, class RetT, class F>
struct A {
F f;
public:
A(F f) : f(f) {}
RetT operator()(ArgT arg) { return f(arg); }
};
Why does this work?
template <class ArgT, class RetT, class F>
class B {
A<ArgT, RetT, F> test;
};
... and this not ?
class C {
template <class ArgT, class RetT, class F>
A<ArgT, RetT, F> test;
};
error C3857: 'C::test': multiple template parameter lists are not allowed
I need to define a class like in last example (class C), how can I do that?
Because variables can't have template. In fact just classes and functions can have template.
Edit: As Alan Stokes said, in C++14, variables also can have template.