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);
| ^
Related
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
I have a C++ class that has a pointQuery function. Currently, when I have to switch between linear and binary search, I comment the other part of the code. I saw this post, and tried to refactor my code. My code goes something as:
namespace searchStrategy{
struct linearSearch{};
struct binarySearch{};
}
template<typename T, typename LookupStrategy> class leaf:public rtNode<T>{
public:T points[maxCapLeaf][d]; // search to be done on this array
// some other class members, most of which used in the search
template<typename searchStrategy::linearSearch> bool pointQuery(const T* f) const{
// some code
}
template<typename searchStrategy::binarySearch> bool pointQuery(const T* f) const{
// some code
}
};
The class' objects are created as:
leaf<T, LookupStrategy>* temp = new leaf<T, LookupStrategy>(some_input_params);
where LookupStrategy is searchStrategy::binarySearch or searchStrategy::linearSearch.
When I compile it, I get the following error:
/file_address/template.cpp:164:39: error: non-type template parameters of class type only available with ‘-std=c++2a’ or ‘-std=gnu++2a’
164 | template<typename searchStrategy::linearSearch> bool pointQuery(const T* f) const{
| ^~~~~~~~~~~~
/file_address/template.cpp:200:39: error: non-type template parameters of class type only available with ‘-std=c++2a’ or ‘-std=gnu++2a’
200 | template<typename searchStrategy::binarySearch> bool pointQuery(const T* f) const{
| ^~~~~~~~~~~~
/file_address/template.cpp:200:58: error: ‘template<class T, class LookupStrategy> template<<typeprefixerror><anonymous> > bool leaf<T, LookupStrategy>::pointQuery(const T*) const’ cannot be overloaded with ‘template<class T, class LookupStrategy> template<<typeprefixerror><anonymous> > bool leaf<T, LookupStrategy>::pointQuery(const T*) const’
200 | template<typename searchStrategy::binarySearch> bool pointQuery(const T* f) const{
| ^~~~~~~~~~
/file_address/template.cpp:164:58: note: previous declaration ‘template<class T, class LookupStrategy> template<<typeprefixerror><anonymous> > bool leaf<T, LookupStrategy>::pointQuery(const T*) const’
164 | template<typename searchStrategy::linearSearch> bool pointQuery(const T* f) const{
|
Can someone please explain what am I doing wrong, and how can I fix this? (Please note that the function needs to remain in the class itself, I can't shift it to the namespace because a lot of class members are used in the search functions) Thanks...
namespace searchStrategy {
struct linearSearch{};
struct binarySearch{};
}
template<typename T, typename LookupStrategy> class leaf: public rtNode<T> {
private:
// Overload 1
bool pointQuery(const T* f, linearSearch) const {
// some code
}
// Overload 2
bool pointQuery(const T* f, binarySearch) const {
// some code
}
public:
T points[maxCapLeaf][d];
bool pointQuery(const T* f) const {
return pointQuery(points, LookupStrategy{});
}
};
(partial) specialization might be a solution, but member/function cannot be partial specialized, you might then partial specialize the whole class.
As alternatives,
In C++17, you might use if constexpr:
bool pointQuery(const T* f) const
{
if constexpr (std::is_same_v<LookupStrategy, searchStrategy::linearSearch>)
// some code
} else { // searchStrategy::binarySearch
// some code
}
}
In C++20, requires:
bool pointQuery(const T* f) const
requires(std::is_same_v<LookupStrategy, searchStrategy::linearSearch>)
{
// some code
}
bool pointQuery(const T* f) const
requires(std::is_same_v<LookupStrategy, searchStrategy::binarySearch>)
{
// some code
}
In previous standard, you might use tag dispatching:
private:
bool pointQuery(searchStrategy::linearSearch, const T* f) const
{
// some code
}
bool pointQuery(searchStrategy::binarySearch, const T* f) const
{
// some code
}
public:
bool pointQuery(const T* f) const
{
return pointQuery(LookupStrategy{}, f);
}
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
Trying to specialize member methods.
Reading this previous question: std::enable_if to conditionally compile a member function
I can quite understand what I am doing wrong.
#include <string>
#include <iostream>
#include <type_traits>
template<typename T>
class Traits
{
};
struct Printer
{
template<typename T>
typename std::enable_if<!std::is_function<decltype(Traits<T>::converter)>::value, void>::type
operator()(T const& object)
{
std::cout << object;
}
template<typename T>
typename std::enable_if<std::is_function<decltype(Traits<T>::converter)>::value, void>::type
operator()(T const& object)
{
std::cout << Traits<T>::converter(object);
}
};
template<>
class Traits<std::string>
{
public:
static std::size_t converter(std::string const& object)
{
return object.size();
}
};
int main()
{
using namespace std::string_literals;
Printer p;
p(5);
p("This is a C-string");
p("This is a C++String"s); // This compiles.
}
Compilation Gives:
> g++ -std=c++1z X.cpp
X.cpp:42:5: error: no matching function for call to object of type 'Printer'
p(5);
^
X.cpp:14:5: note: candidate template ignored: substitution failure [with T = int]: no member named 'converter' in 'Traits<int>'
operator()(T const& object)
^
X.cpp:20:5: note: candidate template ignored: substitution failure [with T = int]: no member named 'converter' in 'Traits<int>'
operator()(T const& object)
^
They both seem to fail because they can't see the method converter. But I am trying to use SFINE and std::enable_if to recognize that this function does not exist and thus only instantiate one of the methods.
The same error is generated for each of the types:
X.cpp:43:5: error: no matching function for call to object of type 'Printer'
p("This is a C-string");
^
X.cpp:14:5: note: candidate template ignored: substitution failure [with T = char [19]]: no member named 'converter' in 'Traits<char [19]>'
operator()(T const& object)
^
X.cpp:20:5: note: candidate template ignored: substitution failure [with T = char [19]]: no member named 'converter' in 'Traits<char [19]>'
operator()(T const& object)
^
Note: It compiles for the std::string version.
You could defer to a private helper function, and use overload resolution to prefer to the positively SFINAE-d overload - and not have a negatively SFINAE-d one:
struct Printer
{
template <class T>
void operator()(T const& object) {
call_impl(object, 0);
}
private:
// selected if Traits<T>::converter exists and is a function
// preferred in this case because int is better than ...
template<typename T>
typename std::enable_if<std::is_function<decltype(Traits<T>::converter)>::value, void>::type
call_impl(T const& object, int)
{
std::cout << Traits<T>::converter(object);
}
// selected if either Traits<T>::converter doesn't exist or isn't a function
template<typename T>
void call_impl(T const& object, ...)
{
std::cout << object;
}
};
One of the nice benefits that we'll get in C++2a with constraining functions is that we can do this without the extra helper:
struct Printer
{
template <class T>
requires std::is_function<decltype(Traits<T>::converter)>::value
void operator()(T const& object)
{
std::cout << Traits<T>::converter(object);
}
template <class T>
void operator()(T const& object)
{
std::cout << object;
}
};
The problem is in how SFINAE works. When substitution fails, the entire function is taken out of the program. So even though your predicate typename std::enable_if<!std::is_function<decltype(Traits<T>::converter)>::value, void>::type is meant to catch the false case, the non-existence of converter will cause the overload to be taken off the table.
The easiest workaround is something like this:
struct Printer
{
template<typename T>
void
impl(T const& object, ...)
{
std::cout << object;
}
template<typename T>
typename std::enable_if<std::is_function<decltype(Traits<T>::converter)>::value, void>::type
impl(T const& object, void*)
{
std::cout << Traits<T>::converter(object);
}
template<typename T>
void
operator()(T const& x)
{
return impl(x, nullptr);
}
};
Basically: You give the compiler something that will always work without using the predicate. The trick here is that nullptr will be matched to void* instead of ..., so it will do what you want.
If you want to get real fun about it, you can make a has_converter function whose return type is true_type or false_type and overload the implementation on that.
struct Printer
{
template<typename T>
std::false_type
has_converter(T const& object, ...);
template<typename T>
typename std::enable_if<std::is_function<decltype(Traits<T>::converter)>::value, std::true_type>::type
has_converter(T const& object, void*);
template<typename T>
void impl(T const& x, std::false_type)
{
std::cout << x;
}
template<typename T>
void impl(T const& x, std::true_type)
{
std::cout << Traits<T>::converter(x);
}
template<typename T>
void
operator()(T const& x)
{
return impl(x, decltype(has_converter(x, nullptr))());
}
};
One can imagine a helper function or templated constexpr bool to make using this property even easier (use the same technique as above).
template <typename T>
constexpr bool has_converter = ???;
How about adding non-function converter to non-specialized trait?
template<typename T>
class Traits
{
public: enum class Dummy{nothing};
public: static Dummy const converter = Dummy::nothing;
};
Run this code online
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))... };
}