let's say you have a class A (C++17):
template<class T>
struct A
{
A() = default;
A(T t) : val(t)
{
}
A operator*(A a)
{
return A(a.val * this->val);
}
T val;
};
However, 99% of the time the value-type of A is going to be an int, so you use a deduction guide to reduce the verbosity:
A()->A<int>;
So that's cool, now you can define variables without the template list:
A myVar;
The problem I'm having is that it seems to break down when it comes to function signatures, for example the following requires use of a template argument list:
auto ASquared = [](A a, A b) { return a * b; };
error C2955: 'A': use of class template requires template argument
list
When I wanted it to deduce that A was A<int>.
My question is: is this an inherent limitation, or am I just missing a different deduction guide that could make this syntax work?
The language doesn't allow this. Deduction doesn't take place within a function signature because there's nothing to deduce from.
Related
I need to pass a unique pointer to a derived template class to a function that takes a unique base template class, like this:
template <typename T>
class Base {};
template <typename T>
class Derived : public Base<T> {};
template <typename T>
void foo(std::unique_ptr<Base<T>>){}
//or
template <typename T>
class MyClass{
public:
MyClass(std::unique_ptr<Base<T>> arg) : _arg(std::move(arg)) {}
private:
std::unique_ptr<Base<T>> _arg;
};
int main()
{
auto b = make_unique<Derived<int>>();
foo(std::move(b));
MyClass mc(std::move(b))
}
Why is this not working and how can I fix it?
I get an error:
'void foo1<T>(std::unique_ptr<Base<T>,std::default_delete<Base<T>>>)': cannot convert argument 1 from 'std::unique_ptr<Derived<int>,std::default_delete<Derived<int>>>' to 'std::unique_ptr<Base<T>,std::default_delete<Base<T>>>'
but it work
auto derived = std::make_unique<Derived<int>>();
std::unique_ptr<Base<int>> base = std::move(derived);
C++ doesn't deduce template arguments in this situation. You can specify <int>, and that will succeed.
foo<int>(std::move(b)); // fine
MyClass<int> mc(std::move(b)); // fine
See it on coliru
You can't have template argument deduction also consider implicit conversions, at least not in most situations. Normally the argument type must match the parameter type exactly for deduction of a template argument to be possible (in this case to deduce T), but std::unique_ptr<Base<int>> and std::unique_ptr<Dervived<int>> are not the same type.
As the other answer suggests you can explicitly specify the template argument instead of trying to have it be deduced.
If you want to automate this without having to add anything to Derived or Base you can however make use of one of the exceptions to the general rule above. If the template parameter is a reference-to or pointer-to base of the argument type, then it may (with certain conditions) still be used for deduction:
// Here an exception to the deduction rules applies
// and `Base<T>*` can be deduced against a pointer `X*`
// if `X` is (uniquely) derived from a `Base<T>`
template<typename T>
auto as_base_ptr(Base<T>* p){
return p;
}
template<typename X>
auto to_base_unique_ptr(std::unique_ptr<X> p) {
using base_type = std::remove_pointer_t<decltype(as_base_ptr(std::declval<X*>()))>;
return std::unique_ptr<base_type>(std::move(p));
}
template <typename T>
void foo(std::unique_ptr<Base<T>>){
}
template <typename X>
void foo(std::unique_ptr<X> p){
foo(to_base_unqiue_ptr(std::move(p)));
}
But even simpler you can ask yourself whether you really need to have the function foo take std::unique_ptr<Base<T>> specifically (e.g. because you need access to T) or whether std::unique_ptr<X> wouldn't already be enough.
I have the following code
template< typename T>
struct S{
T x,y;
S(T a, T b) : x(a) , y(b) {}
};
using Di = S<int>;
using Dd = S<double>;
auto foo(Dd d){
..........
}
Now my doubt is: suppose I am calling foo() with parameter of type Di then it's an error of incorrect reference type.
I know that one solution is to use auto here as it works . But in general I want to know is there any other method so that my function works for both parameter types.
You can make the function a template:
template<typename T>
auto foo(S<T> d){
// ...
}
Now you can call foo with any instantiation of S.
If you want to constrain the function template to only accept instantiations of S with either int or double, you can do that check inside the function:
template<typename T>
auto foo(S<T> d){
static_assert(std::is_same_v<T, int> || std::is_same_v<T, double>);
// ...
}
S<int> and S<double> (a.k.a. Di and Dd) are two different types.
Period.
It doesn't matter that they are template instantiations.
So, do what you'd normally do when you need a function to take an argument of one of two or more types:
make it take a variant, or
make it a template, or
write an overload
I have the following template class :
template <typename T>
struct timer
{
T period;
timer(T p) :
period(p)
{}
};
To instantiate it I need to do :
timer<double> t(double(0.0));
Is is possible to improve timer's class definition to allow this syntax :
timer t(double(0.0));
and have the compiler infer the double type from the constructor's argument ?
No, you can't do that. Type inference doesn't occur in those situations. You could use the auto keyword and a function template to make things easier though:
template<typename T>
timer<T> make_timer(T value) {
return value;
}
// let the compiler deduce double
auto t = make_timer(0.0);
Note that this use of the auto keyword is only valid in the C++11 standard.
Moreover, for this specific situation, you could typedef a double timer:
typedef timer<double> timer_d;
timer_d t(0.0);
Though I'd still go with the first solution, if you're able to use C++11.
No, it's not possible, deduction only works in functions. The usual solution is to write a make_ function which returns a new instance. This is C++11:
template <typename T>
timer<T> make_timer(T&& p) {
return timer<T>(std::forward<T>(p));
}
auto t = make_timer(0.0);
template<typename T>
Ref<Iterator<T> > GetFilterIterator(Ref<Iterator<T> > i, boost::function<bool(T)> pred) {
return new FilterIterator<T>(i, pred);
}
Ref<Iterator<CWorm*> > x = GetFilterIterator(worms(), &CWorm::getLocal);
And worms() returns a Ref<Iterator<CWorm*> Ref> and there is bool CWorm::getLocal(); (which is a member function). And:
template<typename T> struct Ref {
// ...
};
template<typename T> struct Iterator {
// ...
};
This will fail to deduce the template argument:
Iter.h:272:27: note: candidate template ignored: failed template argument deduction [3]
Why?
If I call it with the specified template argument, i.e. GetFilterIterator<CWorm*>(worms(), &CWorm::getLocal), it doesn't complain. I wonder why it cannot deduce the template argument like this. And can I make it different somehow so that it would be able to automatically deduce the type?
Do you mean typname Iterator<T>::Ref for the type of the first parameter in the GetFilterIterator template declaration? If so, that is not a deducible context for template type parameters.
Consider:
template<>
struct Iterator<Foo> {
typedef int Ref;
};
template<>
struct Iterator<Bar> {
typedef int Ref;
};
GetFilterIterator(int(0),f);
Both Iterator<Foo>::Ref and Iterator<Bar>::Ref match the parameter passed to GetFilterIterator, an int. Which one should it pick? C++ disallows deducing template types from parameters like the one you've declared.
With the update to your question it looks like you do mean ::Ref<Iterator<T> >. I think that should be deducible then, and since the typedef Iterator<CWorm*>::Ref is ::Ref<Iterator<CWorm*> > it seems like it should be able to deduce T. I'm not sure why it's not working.
The compiler cannot deduce the template arguments because fitting to the parameters would mean a non-trivial conversion - first to Iterator<T> and then to Ref<Iterator<T> > which both require user-defined conversions. Also, directly converting the member function pointer to boost::function is similarly non-trivial for the compiler.
IBM has a list of supported template parameter deductions.
If you want your template arguments to be deduced automatically, you have to provide wrapper methods:
template <typename T>
Ref<Iterator<T> > makeIteratorRef(T val) {
return Ref<Iterator<T> >(Iterator<T>(val));
}
template <typename T>
boost::function<bool (T)> makeFn(bool (T::*fn) () const) {
boost::function<bool (T)> res = boost::bind(fn, _1);
return res;
}
...
Ref<Iterator<CWorm*> > x = GetFilterIterator(makeIteratorRef(worms()), makeFn(&CWorm::getLocal));
This way the compiler is capable of deducing the template parameters because no conversions are necessary.
By the way, I think you are overcomplicating simple things:
for (auto it = worms().begin(); it != worms().end(); ++it)
if (it->isLocal()) {
// Do something
}
This code is way more readable in C++ and even though it might not be as general it hardly makes the code worse.
Thanks to the hint from Xeo to here about that implicit type conversions are not allowed when deducing template arguments, I wondered wether the second parameter might cause problems here. I thought that it would do the type deduction from left to right and once the type is deducted, it is not a problem anymore (for the function pointer to boost::function cast).
It seems I was wrong and this was exactly the problem.
Another version of the same thing avoids the problem:
template<typename T>
struct PartialFuncWrapper {
::Ref<Iterator<T> > i;
PartialFuncWrapper(::Ref<Iterator<T> > _i) : i(_i) {}
typename Iterator<T>::Ref operator()(boost::function<bool(T)> pred) {
return new FilterIterator<T>(i, pred);
}
};
template<typename T>
PartialFuncWrapper<T> GetFilterIterator(::Ref<Iterator<T> > i) {
return PartialFuncWrapper<T>(i);
}
Then I can write:
Ref<Iterator<CWorm*> > x = GetFilterIterator(worms())(&CWorm::getLocal);
Is there a way to have the compile deduce the template parameter automatically?
template<class T>
struct TestA
{
TestA(T v) {}
};
template<class T>
void TestB(T v)
{
}
int main()
{
TestB (5);
}
Test B works fine, however when i change it to TestA it will not compile with the error " use of class template requires template argument list"
No, there isn't. Class templates are never deduced. The usual pattern is to have a make_ free function:
template<class T> TestA<T> make_TestA(T v)
{
return TestA<T>(v);
}
See std::pair and std::make_pair, for example.
In C++0x you will be able to do
auto someVariable = make_TestA(5);
to avoid having to specify the type for local variables.
Sunlight is right, but if I may ask you a question: is that really a problem in your code. I mean:
TestA(5);
Would become
TestA<int>(5);
As long as it's only one template argument, it's not that bad, IMHO. It's not like you can get around typing the type once in most cases.