Variadic templates and C arrays - c++

I'm trying to compile the following piece of code:
template <typename T, int N> void foo( const T (&array)[N]) {}
template <typename T> static int args_fwd_(T const &t) { foo(t); return 0; }
template<class ...Us> void mycall(Us... args) {
int xs[] = { args_fwd_(args)... };
}
int main(void) {
int b[4];
mycall(b);
}
The mycall function uses variadic templates and then forwards to the args_fwd_ function to call the function foo on each argument.
This works fine for most argument types (assuming I have appropriately defined foo functions). But when I try to pass a C-style array (int b[4]) it gets turned into a pointer and then it can't find the templated foo function that requires an array (not pointer). The error from gcc 4.9.3 is as follows:
error: no matching function for call to ‘foo(int* const&)’
note: candidate is:
note: template<class T, int N> void foo(const T (&)[N])
template <typename T, int N> void foo( const T (&array)[N]) {}
note: template argument deduction/substitution failed:
note: mismatched types ‘const T [N]’ and ‘int* const’
Note the part about looking for a pointer. This is the same in clang as well so apparently this is standard compliant. Is there a way to preserve that this is a C array without it getting converted to a pointer?

Yes. Use perfect forwarding:
#include <utility>
template<class ...Us> void mycall(Us&&... args) {
int xs[] = { args_fwd_(std::forward<Us>(args))... };
}

Related

C++ template function dependent typename not recognized

In the following mcve:
template <typename T> class Class { public: class MemberClass {}; };
#include <list>
template <typename T>
Class<T> func(const typename Class<T>::MemberClass& start,
const typename Class<T>::MemberClass& finish)
{
Class<T> result; return result;
}
int main ()
{
Class<int>::MemberClass i, j;
Class<int> L2; L2 = func(i, j);
return 0;
}
I find that the compiler does not recognize the function as something that can take the given arguments. In Visual Studio the error is
1>C:\...\main.cpp(15,25): error C2672: 'func': no matching overloaded function found
1>C:\...\main.cpp(15,34): error C2783: 'Class<T> func(const Class<T>::MemberClass &,const Class<T>::MemberClass &)': could not deduce template argument for 'T'
1>C:\...\main.cpp(6): message : see declaration of 'func'
In g++, here are the errors:
main.cpp:15:34: error: no matching function for call to 'func(Class<int>::MemberClass&, Class<int>::MemberClass&)'
15 | Class<int> L2; L2 = func(i, j);
| ^
main.cpp:6:10: note: candidate: 'template<class T> Class<T> func(const typename Class<T>::MemberClass&, const typename Class<T>::MemberClass&)'
6 | Class<T> func(const typename Class<T>::MemberClass& start,
| ^~~~
main.cpp:6:10: note: template argument deduction/substitution failed:
main.cpp:15:34: note: couldn't deduce template parameter 'T'
15 | Class<int> L2; L2 = func(i, j);
| ^ ^
I'm sure there's another way to write the function (it could return a MemberClass not a Class), but, well, this should be doable. How can I make that happen?
If you want to do it without specifying a template type for func, you can make the type of Class<T> known to the MemberClass and have the compiler resolve T within the func function template to Class<T>::MemberClass instead of the T within Class<T>.
This is very easy for the compiler, since it is the type of the arguments of func:
template <typename T>
class Class {
public:
class MemberClass { public: using ParentClass = Class<T>; };
};
#include <list>
template <typename T>
typename T::ParentClass func(const T& start,
const T& finish)
{
typename T::ParentClass result; return result;
}
int main ()
{
Class<int>::MemberClass i, j;
Class<int> L2; L2 = func(i, j);
return 0;
}
Quite literally, every possible T that matches your Class has a MemberClass type. The compiler is not going to look inside all of them to find a match, because it'd have to instantiate templates just to see their contents, and it would potentially match too many things. So the langauge simply doesn't look inside like that.
The way you can solve this is to tell the compiler what T is when you call it, here, providing an explicit int template argument:
func<int>(i, j);
In
template <typename T>
Class<T> func(const typename Class<T>::MemberClass&,
const typename Class<T>::MemberClass&);
T is not deducible (left of ::).
You have several options:
Make a friend non-template function inside MemberClass (will be found by ADL):
template <typename T> class Class {
public:
class MemberClass {
friend Class func(const MemberClass& start, const MemberClass& finish)
{
Class result; return result;
}
};
};
Demo
Be more generic of accepted type (you need here to give a way to retrieve Class from MemberClass):
template <typename T> class Class {
public:
class MemberClass {
public:
using ParentClass = Class;
};
};
template <typename T>
typename T::ParentClass func(const T& start, const T& finish)
{
typename T::ParentClass result; return result;
}
Demo

Template deduction failed

I've been trying to implement some generic wrappers (similar to std::span). However, I can't seem to get the template deduction/ conversion working. I'm not sure why. Below is a minimum "not-compiling" example
#include <array>
#include <iostream>
template<typename T>
class Wrapper
{
public:
using ElementType = T;
using ValueType = std::remove_cv<T>;
using Pointer = ElementType*;
constexpr Wrapper(const Wrapper& lhs):
mPtr(lhs.mPtr)
{}
template<typename U, std::size_t N>
Wrapper(const std::array<U,N>& lhs):
mPtr(lhs.data())
{}
template<typename U, std::size_t N>
Wrapper(std::array<U,N>& lhs):
mPtr(lhs.data())
{}
Pointer mPtr;
};
// Deduction guidelines
template <typename Type, std::size_t Size>
Wrapper(std::array<Type, Size>&)->Wrapper<Type>;
template <typename Type, std::size_t Size>
Wrapper(const std::array<Type, Size>&)->Wrapper<const Type>;
/// The function that is supposed convert array to the Wrapper
template<typename T>
void TestFunction(const Wrapper<T>& data)
{
// do something with the data
std::cout << data.mPtr;
}
// Try and use Test Function passing in an array
void LetsTest(std::array<float, 128>& data)
{
TestFunction(data);
}
Could someone please explain what I am missing or not understanding?
The compiler complaint is
#1 with ARM gcc 10.2.1 (none) : In function 'void LetsTest(std::array<float, 128>&)': :47:22: error: no matching
function for call to 'TestFunction(std::array<float, 128>&)' 47 |
TestFunction(data);
| ^ :38:6: note: candidate: 'template<class T, class U> void TestFunction(const Wrapper&)'
38 | void TestFunction(const Wrapper& data)
| ^~~~~~~~~~~~ :38:6: note: template argument deduction/substitution failed: :47:22: note:
'std::array<float, 128>' is not derived from 'const Wrapper'
47 | TestFunction(data);
| ^

explicit template specialization from function template not working

I am trying to do explicit specialization for a template function called from another template function. Following is a minimum non-working example and I am trying to implement the following idea:
CInt, CDouble and CStr are equivalent of operations that I need to perform. But, CStr constructor expects a little different format.
MyClass is equivalent of a factory, which when requested will return one of the instances of CInt, CDouble or CStr.
The motivation for this structure: Assume that GetCClass function is called from a function with ~100 lines and only one difference: the type of class. The values returned from GetCClass have same APIs.
#include <iostream>
#include <memory>
#include <string>
using namespace std;
class CStrArg {
public:
const char* a;
int size;
};
class MyClass {
public:
class CStr;
class CInt;
class CDouble;
template <typename T>
typename T::Ptr GetCClass(typename T::ArgType arg);
template <typename T>
typename T::Ptr GetCClassInternal(typename T::ArgType arg);
};
class MyClass::CInt {
public:
typedef int ArgType;
typedef shared_ptr<CInt> Ptr;
static Ptr CreatePtr(ArgType i) { return Ptr(new CInt(i)); }
private:
CInt(ArgType i) : i_(i) {}
ArgType i_;
};
class MyClass::CDouble {
public:
typedef double ArgType;
typedef shared_ptr<CDouble> Ptr;
static Ptr CreatePtr(ArgType d) { return Ptr(new CDouble(d)); }
private:
CDouble(ArgType i) : i_(i) {}
ArgType i_;
};
class MyClass::CStr {
public:
typedef CStrArg ArgType;
typedef shared_ptr<CStr> Ptr;
static Ptr CreatePtr(string s) { return Ptr(new CStr(s)); }
private:
CStr(string i) : i_(i) {}
string i_;
};
//template definition
template <typename T>
typename T::Ptr MyClass::GetCClass(typename T::ArgType arg) {
return GetCClassInternal(arg);
}
template <typename T>
typename T::Ptr MyClass::GetCClassInternal(typename T::ArgType arg) {
cout << "GetCClass for all types but one" << endl;
return T::CreatePtr(arg);
}
template <>
MyClass::CStr::Ptr MyClass::GetCClassInternal<MyClass::CStr>(CStrArg arg) {
return CStr::CreatePtr(arg.a);
}
int main() {
MyClass test;
int i = 5;
double d = 1.2;
CStrArg s;
s.a = "why me";
s.size = 6;
auto iptr = test.GetCClass(i);
auto dptr = test.GetCClass(d);
auto sptr = test.GetCClass(s);
return 0;
}
I get the following error:
experimental/amandeep/proto_test/fn_template_sp.cc:88:31: note: candidate is:
experimental/amandeep/proto_test/fn_template_sp.cc:20:19: note: template<class T> typename T::Ptr MyClass::GetCClass(typename T::ArgType)
typename T::Ptr GetCClass(typename T::ArgType arg);
^
experimental/amandeep/proto_test/fn_template_sp.cc:20:19: note: template argument deduction/substitution failed:
experimental/amandeep/proto_test/fn_template_sp.cc:88:31: note: couldn't deduce template parameter ‘T’
auto iptr = test.GetCClass(i);
^
experimental/amandeep/proto_test/fn_template_sp.cc:89:31: error: no matching function for call to ‘MyClass::GetCClass(double&)’
auto dptr = test.GetCClass(d);
^
experimental/amandeep/proto_test/fn_template_sp.cc:89:31: note: candidate is:
experimental/amandeep/proto_test/fn_template_sp.cc:20:19: note: template<class T> typename T::Ptr MyClass::GetCClass(typename T::ArgType)
typename T::Ptr GetCClass(typename T::ArgType arg);
^
experimental/amandeep/proto_test/fn_template_sp.cc:20:19: note: template argument deduction/substitution failed:
experimental/amandeep/proto_test/fn_template_sp.cc:89:31: note: couldn't deduce template parameter ‘T’
auto dptr = test.GetCClass(d);
^
experimental/amandeep/proto_test/fn_template_sp.cc:90:31: error: no matching function for call to ‘MyClass::GetCClass(CStrArg&)’
auto sptr = test.GetCClass(s);
^
experimental/amandeep/proto_test/fn_template_sp.cc:90:31: note: candidate is:
experimental/amandeep/proto_test/fn_template_sp.cc:20:19: note: template<class T> typename T::Ptr MyClass::GetCClass(typename T::ArgType)
typename T::Ptr GetCClass(typename T::ArgType arg);
^
experimental/amandeep/proto_test/fn_template_sp.cc:20:19: note: template argument deduction/substitution failed:
experimental/amandeep/proto_test/fn_template_sp.cc:90:31: note: couldn't deduce template parameter ‘T’
auto sptr = test.GetCClass(s);
I have read multiple answers, but I cannot understand why this is not working. Any help is appreciated.
EDIT:
I cannot understand, but locally in my actual code I get the following:
/home/workspace/main/util/storage/smb2_proxy/smb2_proxy.cc:239:29: error: template-id ‘CreateOp<storage::smb2_proxy::Smb2Proxy::PurgeTaskOp>’ for ‘storage::smb2_proxy::Smb2Proxy::PurgeTaskOp::Ptr storage::smb2_proxy::Smb2Proxy::CreateOp(std::shared_ptr<storage::smb2_proxy::Smb2Proxy::TaskState>,storage::smb2_proxy::Smb2Proxy::PurgeTaskOp::ArgType&,storage::smb2_proxy::Smb2Proxy::PurgeTaskOp::ResultType*,storage::smb2_proxy::Smb2Proxy::DoneCb)’ does not match any template declaration
Smb2Proxy::PurgeTaskOp::Ptr Smb2Proxy::CreateOp<Smb2Proxy::PurgeTaskOp>(
^~~~~~~~~
In file included from /home/workspace/main/util/storage/smb2_proxy/smb2_proxy.cc:5:0:
/home/workspace/main/util/storage/smb2_proxy/smb2_proxy.h:160:20: note: candidate is: template<class Op> typename Op::Ptr storage::smb2_proxy::Smb2Proxy::CreateOp(std::shared_ptr<storage::smb2_proxy::Smb2Proxy::TaskState>, const typename Op::ArgType&, typename Op::ResultType*,storage::smb2_proxy::Smb2Proxy::DoneCb)
typename Op::Ptr CreateOp(std::shared_ptr<TaskState> task_state,
CreateOp -> GetCClassInternal (both are equivalent)
The compiler is not able to take specialization of CreateOp and complains that it does not match any declaration.
PS: I had another question in which I had made a mistake while posting the code. I have deleted the question and am reposting it.
The problem is that the template parameter T of GetCClass (and GetCClassInternal) is used in non-deduced contexts, it can't be deduced.
If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.
1) The nested-name-specifier (everything to the left of the scope resolution operator ::) of a type that was specified using a qualified-id:
You can specify the template argument explicitly. e.g.
auto iptr = test.GetCClass<MyClass::CInt>(i);
auto dptr = test.GetCClass<MyClass::CDouble>(d);
auto sptr = test.GetCClass<MyClass::CStr>(s);
LIVE

Typesafe variadic function

I want to write a function that accepts a variable number of string literals. If I was writing in C, I would have to write something like:
void foo(const char *first, ...);
and then the call would look like:
foo( "hello", "world", (const char*)NULL );
It feels like it ought to be possible to do better in C++. The best I have come up with is:
template <typename... Args>
void foo(const char* first, Args... args) {
foo(first);
foo(args);
}
void foo(const char* first) { /* Do actual work */ }
Called as:
foo("hello", "world");
But I fear that the recursive nature, and the fact that we don't do any type checking until we get to a single argument, is going to make errors confusing if somebody calls foo("bad", "argument", "next", 42). What I want to write, is something like:
void foo(const char* args...) {
for (const char* arg : args) {
// Real work
}
}
Any suggestions?
Edit: There is also the option of void fn(std::initializer_list<const char *> args), but that makes the call be foo({"hello", "world"}); which I want to avoid.
I think you probably want something like this:
template<class... Args,
std::enable_if_t<(std::is_same_v<const char*, Args> && ...), int> = 0>
void foo(Args... args ){
for (const char* arg : {args...}) {
std::cout << arg << "\n";
}
}
int main() {
foo("hello", "world");
}
Note: it is not possible to match just string literals. The closest you can come is to match a const char array.
To do the type checking, use a function template which takes const char arrays.
To loop over them with range-based for, we need to convert it to an initializer_list<const char*>. We can do so directly with braces in the range-based for statement, because arrays will decay to pointers.
Here is what the function template looks like (note: this works on zero or more string literals. If you want one or more, change the function signature to take at least one parameter.):
template<size_t N>
using cstring_literal_type = const char (&)[N];
template<size_t... Ns>
void foo(cstring_literal_type<Ns>... args)
{
for (const char* arg : {args...})
{
// Real work
}
}
While all other answers solve the problem, you could also do the following:
namespace detail
{
void foo(std::initializer_list<const char*> strings);
}
template<typename... Types>
void foo(const Types... strings)
{
detail::foo({strings...});
}
This approach seems (at least to me) to be more readable than using SFINAE and works with C++11. Moreover, it allows you to move implementation of foo to a cpp file, which might be useful too.
Edit: at least with GCC 8.1, my approach seems to produce better error message when called with non const char* arguments:
foo("a", "b", 42, "c");
This implementation compiles with:
test.cpp: In instantiation of ‘void foo_1(const ArgTypes ...) [with ArgTypes = {const char*, int, const char*, const char*}]’:
test.cpp:17:29: required from here
test.cpp:12:16: error: invalid conversion from ‘int’ to ‘const char*’ [-fpermissive]
detail::foo({strings...});
~~~~~~~~~~~^~~~~~~~~~~~~~
While SFINAE-based (liliscent's implementation) produces:
test2.cpp: In function ‘int main()’:
test2.cpp:14:29: error: no matching function for call to ‘foo(const char [6], const char [6], int)’
foo("hello", "world", 42);
^
test2.cpp:7:6: note: candidate: ‘template<class ... Args, typename std::enable_if<(is_same_v<const char*, Args> && ...), int>::type <anonymous> > void foo(Args ...)’
void foo(Args... args ){
^~~
test2.cpp:7:6: note: template argument deduction/substitution failed:
test2.cpp:6:73: error: no type named ‘type’ in ‘struct std::enable_if<false, int>’
std::enable_if_t<(std::is_same_v<const char*, Args> && ...), int> = 0>
+1 for the C++17 liliscent's solution.
For a C++11 solution, a possible way is create a type traits to make an "and" of multiple values (something similar to std::conjunction that, unfortunately, is available only starting from C++17... when you can use folding and you don't need std::conjunction anymore (thanks liliscent)).
template <bool ... Bs>
struct multAnd;
template <>
struct multAnd<> : public std::true_type
{ };
template <bool ... Bs>
struct multAnd<true, Bs...> : public multAnd<Bs...>
{ };
template <bool ... Bs>
struct multAnd<false, Bs...> : public std::false_type
{ };
so foo() can be written as
template <typename ... Args>
typename std::enable_if<
multAnd<std::is_same<char const *, Args>::value ...>::value>::type
foo (Args ... args )
{
for (const char* arg : {args...}) {
std::cout << arg << "\n";
}
}
Using C++14, multAnd() can be written as a constexpr function
template <bool ... Bs>
constexpr bool multAnd ()
{
using unused = bool[];
bool ret { true };
(void)unused { true, ret &= Bs ... };
return ret;
}
so foo() become
template <typename ... Args>
std::enable_if_t<multAnd<std::is_same<char const *, Args>::value ...>()>
foo (Args ... args )
{
for (const char* arg : {args...}) {
std::cout << arg << "\n";
}
}
--- EDIT ---
Jarod42 (thanks!) suggest a far better way to develop a multAnd; something as
template <typename T, T ...>
struct int_sequence
{ };
template <bool ... Bs>
struct all_of : public std::is_same<int_sequence<bool, true, Bs...>,
int_sequence<bool, Bs..., true>>
{ };
Starting from C++14 can be used std::integer_sequence instead of it's imitation (int_sequence).
Using C++17 fold expressions on the comma operator, you can simply do the following:
#include <iostream>
#include <string>
#include <utility>
template<typename OneType>
void foo_(OneType&& one)
{
std::cout << one;
}
template<typename... ArgTypes>
void foo(ArgTypes&&... arguments)
{
(foo_(std::forward<ArgTypes>(arguments)), ...);
}
int main()
{
foo(42, 43., "Hello", std::string("Bla"));
}
Live demo here. Note I used foo_ inside the template, because I couldn't be bothered to write out 4 overloads.
If you really really really want to restrict this to string literals, change the function signature as Nevin's answer suggests:
#include <cstddef>
#include <iostream>
#include <string>
#include <utility>
template<std::size_t N>
using string_literal = const char(&)[N];
template<std::size_t N>
void foo(string_literal<N> literal)
{
std::cout << literal;
}
template<std::size_t... Ns>
void foo(string_literal<Ns>... arguments)
{
(foo(arguments), ...);
}
int main()
{
foo("Hello", "Bla", "haha");
}
Live demo here.
Note this is extremely close to the C++11 syntax to achieve the exact same thing. See e.g. this question of mine.
Well, the nearest you can get to a function accepting any arbitrary number of const char* but nothing else uses a template-function and forwarding:
void foo_impl(std::initializer_list<const char*> args)
{
...
}
template <class... ARGS>
auto foo(ARGS&&... args)
-> foo_impl({std::forward<ARGS>(args)...})
{
foo_impl({std::forward<ARGS>(args)...});
}
The subtlety is in allowing the normal implicit conversions.
#include<type_traits>
#include<iostream>
auto function = [](auto... cstrings) {
static_assert((std::is_same_v<decltype(cstrings), const char*> && ...));
for (const char* string: {cstrings...}) {
std::cout << string << std::endl;
}
};
int main(){
const char b[]= "b2";
const char* d = "d4";
function("a1", b, "c3", d);
//function(a, "b", "c",42); // ERROR
}
And now... for something completely different...
You can write a type wrapper struct as follows
template <typename, typename T>
struct wrp
{ using type = T; };
template <typename U, typename T>
using wrp_t = typename wrp<U, T>::type;
and a foo() function receiving a variadic list of char const * simply become
template <typename ... Args>
void foo (wrp_t<Args, char const *> ... args)
{
for ( char const * arg : {args...} )
std::cout << "- " << arg << std::endl;
}
The problem is that you can't call it as you want
foo("hello", "world");
because the compiler isn't able to deduce the Args... types.
Obviously you can explicit a list of dummy types
foo<void, void>("hello", "world");
but I understand that is a horrible solution.
Anyway, if you accept to pass through a trivial template function
template <typename ... Args>
void bar (Args ... args)
{ foo<Args...>(args...); }
you can call
bar("hello", "world");
The following is a full C++11 working example
#include <iostream>
template <typename, typename T>
struct wrp
{ using type = T; };
template <typename U, typename T>
using wrp_t = typename wrp<U, T>::type;
template <typename ... Args>
void foo (wrp_t<Args, char const *> ... args)
{
for ( char const * arg : {args...} )
std::cout << "- " << arg << std::endl;
}
template <typename ... Args>
void bar (Args ... args)
{ foo<Args...>(args...); }
int main ()
{
bar("hello", "world"); // compile
// bar("hello", "world", 0); // compilation error
}
Of course it is possible, this compiles and runs what you want (pay attention)
#include<iostream>
template<class... Char>
// hehe, here is the secret
auto foo(const Char*... args ) ->decltype((char const*)(*std::begin({args...})), (char const*)(*std::end({args...})), void(0))
{
for (const char* arg : {args...}) {
std::cout << arg << "\n";
}
}
int main() {
foo("no", "sense","of","humor");
}
This is #liliscent solution but with more sugar and, to please #rubenvb, without enable_if.
If you think the extra code as a comment (which is not), note that you'll see exactly the syntax you are looking for.
Note that you can only feed an homogeneous list of things that is convertible to char const*, which was one of your goals it seems.

Extract class from static and templated member functions

Consider the following code:
#include <iostream>
#include <type_traits>
#include <typeinfo>
struct object
{
void f0(int i) {std::cout<<i<<std::endl;}
void f1(int i) const {std::cout<<i<<std::endl;}
void f2(int i) volatile {std::cout<<i<<std::endl;}
void f3(int i) const volatile {std::cout<<i<<std::endl;}
constexpr int f4(int i) const noexcept {return i;}
static void f5(int i) {std::cout<<i<<std::endl;}
template <class T> void f(T i) {std::cout<<i<<std::endl;}
};
template <class T, class C>
void print_class_containing(T C::* ptr)
{
std::cout<<"typeid(C).name() = "<<typeid(C).name()<<std::endl;
}
int main(int argc, char* argv[])
{
std::cout<<"typeid(object).name() = "<<typeid(object).name()<<std::endl;
print_class_containing(&object::f0);
print_class_containing(&object::f1);
print_class_containing(&object::f2);
print_class_containing(&object::f3);
print_class_containing(&object::f4);
//print_class_containing(&object::f5); -> Not compiling
//print_class_containing(&object::f); -> Not compiling
return 0;
}
How to write a function, and how to call it, to print the class that is "containing" a pointer to static member function (f5), and pointer to templated member function (f)?
Currently, the compiler returns:
static_member.cpp:30:5: error: no matching function for call to 'print_class_containing'
print_class_containing(&object::f5); // -> Not compiling
^~~~~~~~~~~~~~~~~~~~~~
static_member.cpp:17:6: note: candidate template ignored: could not match 'T C::*' against 'void (*)(int)'
void print_class_containing(T C::* ptr)
^
static_member.cpp:31:5: error: no matching function for call to 'print_class_containing'
print_class_containing(&object::f); // -> Not compiling
^~~~~~~~~~~~~~~~~~~~~~
static_member.cpp:17:6: note: candidate template ignored: couldn't infer template argument 'T'
void print_class_containing(T C::* ptr)
^
2 errors generated.