My actual usecase takes a few more arguments but it simplifies to this:
template< typename Arg1 >
bool algorithm( Arg1&& p1, **p2 here** );
With just that its evident that Arg1 will collapse in some way and likely become some kind of reference. p1 is also an output of the algorithm and so if the caller chooses to pass in an lvalue, the function will return with the original parameter modified to reflect where it left off.
However p2 is of the same type but will never be modified. So actually I'd like to put a 'const' promise in there for correctness. Clearly if Arg1 deduces to be a reference, I cannot add const to it.
So my solution is this:
template< class T >
struct make_const_ref
{
typedef typename std::add_reference< typename std::add_const< typename std::remove_reference< T >::type >::type >::type type;
};
template< typename Arg1 >
bool algorithm( Arg1&& p1, typename make_const_ref<Arg1>::type p2 );
Which goes through a bunch of silly machinations to remove some qualifiers and then stick the const& back on.
So my questions are:
1) Is this the best way of doing it?
2) Is there a context under which this will fail? Right now it seems pretty good to me.
I can think of one change that is surprising, but does not result in outright failure. The second parameter is disabled from argument deduction, so the type no longer has to match the first parameter type exactly. This allows for implicit conversions to be accepted, as-if the template argument were specified for the function. An example:
struct Foo
{
int value;
operator int() const
{
return value;
}
};
int main()
{
algorithm(0, Foo{0});
}
whereas the expression:
template<typename Arg>
bool algorithm(const Arg& p1, const Arg2& p2)
will fail to compile with algorithm(0, Foo{0}) unless it was explicitly algorithm<int>(0, Foo{0}). If you were hoping for exact matches only, then this could be problematic. In some cases this desirable; boost::clamp is one example I am aware of that does this intentionally.
Bonus
This is similar to some of the comments to your question, but the trait can be simplified:
template<typename Type>
using const_ref_t =
typename std::add_const<
typename std::add_lvalue_reference<Type>::type>::type;
std::add_lvalue_reference will do what you want in all situations.
Edit
I put this as comment but it should probably go here. This is probably easier:
template<typename Arg1>
bool algorithm(Arg1&& p1, const typename std::remove_reference<Arg1>::type& p2)
All you are trying to do is disable argument deduction for the second parameter, and take it by const-reference. This is doing just that.
Related
I have a list of operator overloads, and I found that they are not acting in the way that I want them to. I reduced the problematic code to a couple lines to simulate the problem. I have a couple template type aliases to help compile time decision making, a template function (an operator in the working code, but here just a generic function), and a class called var that takes in two template parameters, an unsigned int and a bool (true = known var, false = unknown var, just mentioning this so that the naming convention in the following code snippet makes sense). Here is the code.
template<typename T>
using is_known = typename std::is_same<T, const var<T::ID, true> >::type;
template<typename T>
using is_unknown = typename std::conditional<is_known<T>::value, std::false_type, std::true_type>::type;
template<typename T>
using UK_if_UK = typename std::enable_if<is_unknown<T>::value, T>::type;
template<typename unknown_check_LHS, typename unknown_check_RHS>
constexpr const two_param_type<UK_if_UK<unknown_check_LHS>, UK_if_UK<unknown_check_RHS> > func(const unknown_check_LHS& lhs, const unknown_check_RHS& rhs)
{
return two_param_type<unknown_check_LHS, unknown_check_RHS>
(//generic construction goes here, unimportant...);
}
int main()
{
constexpr const var<0u,true> firstvar(123);
constexpr const var<1u,true> secondvar(456);
func(firstvar,secondvar);
func<std::decltype(firstvar),std::decltype(secondvar)>(firstvar,secondvar);
}
The two calls to func() seem identical to me, and they should both fail (in the working code there are other options once this function SFINAEs out). However, only the second call, where I explicitly declare the types, does the compiler throw an error. It compiles the first call to func() perfectly, and even worse, it operates and returns with type "known" (var<(some unsigned),true>), even though the type alias in the return type should SFINAE the function out of overload resolution. I am using operators, so explicitly declaring the type is not an option for me. More importantly, however, I want to know why the function is not SFINAEing out. Any help would be appreciated. Thank you.
Note: The specific error is:
error: no matching function for call to 'func(const var<0u, true>&, const var<1u, true>&)'
Also, I have tested is_known, is_unknown, and UK_if_UK to work properly, so no need to test those. Thank you.
The two calls to func seem identical to me
Wrong.
They are different.
It's a constness problem.
With
constexpr const var<0u,true> firstvar(123);
constexpr const var<1u,true> secondvar(456);
and the signature of func() as follows
template<typename unknown_check_LHS, typename unknown_check_RHS>
constexpr /* ... */ func (const unknown_check_LHS & lhs,
const unknown_check_RHS & rhs)
calling
func(firstvar,secondvar);
the types, unknown_check_LHS and unknown_check_RHS, are detected as var<0u, true> and var<1u, true> respectively.
Please observe: var<0u, true> and var<1u, true>, not const var<0u, true> and const var<1u, true>.
On the contrary, explicating the types as follows
func<decltype(firstvar), decltype(secondvar)>(firstvar,secondvar);
(and please: decltype(), not std::decltype()), unknown_check_LHS and unknown_check_RHS are explicated as const var<0u, true> and const var<1u, true> respectively.
Observe that now the types are constant.
Observe how is defined is_know
template<typename T>
using is_known = typename std::is_same<T, const var<T::ID, true> >::type;
It compare the type T with a constant type.
So, in the first case (with template types not-constant), is_known is false; in the second case (with constant template types), it's true.
Suppose we have this code:
template <class T, void (*u)(T&)>
void Foo()
{
// store the function u internally . . .
}
There are reasons to do something like this and I won't attempt to go into them. However, is there any way to avoid having to specify type T when calling Foo()? For example, to compile, one normally needs:
Foo<int, MyIntFunction>();
But if this int can be deduced from the function pointer, is this possible:
Foo<MyIntFunction>();
EDIT I'm aware of the solution to pass the actual function pointer in as a function parameter, however this is not desired here as it has some perf drawbacks in intensive loop.
In this example u is not a function pointer, it's a type (the signature of a function pointer). If you want to store a function pointer you need to pass it.
template<class T, class F = void(*)(T&)>
void Foo(F f)
{
// store the function pointer f here
}
called like so:
struct SomeType {};
void bar(SomeType& x);
Foo(&bar);
Is this what you mean to do?
Short answer: I don't think it is possible.
Long one.. When calling a template function, you cannot omit the first parameter and specify the second: the compiler would try to match your MyIntFunction to the template parameter T. Generally, you can specify the first, but omit the second if the compiler can infer the second template parameter. In this case, this is not an option however, because you want to specify the second parameter explicitly.
The second template parameter has a dependency (T) on the first template parameter. Therefore, reversing the order of the template parameters is also not an option.
Your best bet would be to define it in a way similar to what Richard suggested:
template<class T>
void Foo(T f)
{
int a(1);
f(a); // this forces f to be a function taking an int as parameter
}
Here is a dirty implementation which basically does what the OP was asking for. It depends on too many assumptions, but could be at least something to discuss. The idea is to specify in advance all possible types which can serve as function argument, and then deduce this type.
#include<iostream>
template<typename T>
struct TD; //type display
template<typename FunctionType, typename T, typename ... Ts>
struct ArgumentDeduction
{
typedef typename std::conditional<std::is_same<void, typename std::result_of<FunctionType(T)>::type>::value
, T
, typename ArgumentDeduction<FunctionType, Ts ...>::type
>::type type;
};
template<typename FunctionType, typename T>
struct ArgumentDeduction<FunctionType, T>
{
typedef typename std::conditional<std::is_same<void, typename std::result_of<FunctionType(T)>::type>::value
, T
, void
>::type type;
};
template<typename FunctionType
, typename T = typename ArgumentDeduction<FunctionType, int, double>::type >
void foo()
{
TD<T>();
}
struct AvoidConversion
{
struct DummyType{};
template<typename T> DummyType operator()(T x) { return DummyType(); }
};
struct Bar : public AvoidConversion
{
using AvoidConversion::operator();
void operator()(int x);
//void operator()(double x); //try also this
};
int main()
{
foo<Bar>(); //calls the foo<Bar,int> version
}
One main assumption here is the form of the Bar functor, which in principle accepts any type, but has a relevant implementation of type void only for the single allowed type.
Again, I don't think this is rather useful, but I guess this comes closest to the OP's question up to now.
DEMO
EDIT: Otherwise, i.e. without AvoidConversion in the code above, the compiler will perform an implicit conversion and the argument deduction gives true for all types which are convertible into each other (such that, e.g., int is deduced when there is only a function taking double).
If someone sees a way to avoid this ugly AvoidConversion hack and deduce the parameter type somehow more elegant, I would be interested in seeing that.
I have function template:
template<class Ty,
typename std::enable_if< std::is_arithmetic<Ty>::value >::type* = nullptr >
inline void printBars(std::vector<Ty> const& y,
std::function<Ty(Ty)> const& alt);
I wonder if there is some approach to use the type deduced from first function argument in the second argument in order to make possible to use this function template in such way:
#include <cmath>
printBars(y, log10);
Is there?
Any computer science problem can be solved by another level of indirection.
In the public function just let the second argument be of type U, a second template parameter, and forward the call to the real function implementation.
This approach is also necessary if, for example, you want to differentiate between array and pointer argument.
Example.
namespace detail{
template< class T >
void printBars( std::vector<T> const& y, std::function<T(T)> const& alt)
{
// whatever.
};
} // namespace detail
template<
class T, class U,
class enabled = std::enable_if< std::is_arithmetic<T>::value >::type >
void printBars( std::vector<T> const& y, U const& alt )
{
detail::printBars_impl<T>( y, alt );
};
Disclaimer: code not touched by compilar's hands, + just out bed (no coffee yet). ;-)
Thinking about it, the best here is probably to do as Xeo suggests and entirely dispense with the std::function, for it seem to just impose an unreasonable constraint on the caller; instead just check whether the argument supports what you want to use it for.
I've tried searching for this but every term I think of ends up with totally unrelated results.
I have a function (template) that takes a pointer-to-member as a parameter, but I cannot seem to implicitly treat the member being pointed to as const. Using const_cast works, but I'd like to avoid having to explicitly call it if I can.
struct MyStruct
{
int *_array;
int _size;
};
template<typename C, typename T>
void DoSomething(T* C::* arr, int siz)
{
// do some read-only stuff with the member here
}
template<typename C, typename T>
void ConstDoSomething(T* C::* arr, int siz)
{
DoSomething<C, T const>(arr, siz);
// DoSomething<C, T const>(const_cast<T const* C::*>(arr), siz); // works
}
MyStruct ms;
ConstDoSomething<MyStruct const, int>(&MyStruct::_array, ms._size); // note: cannot convert ‘arr’ (type ‘int* MyStruct::*’) to type ‘const int* MyStruct::*’
This is a simplified example that demonstrates the problem I'm having with a more complex class tree. I'm trying to avoid the cast because it would be required by the calling code (e.g., the person using the class template(s)).
UPDATE: When I first posted this I accidentally used a code sample that didn't generate the same error. It took me a fair amount of testing to determine the root cause, which was that I'm adding the const qualifier in the template arguments. The above sample now properly demonstrates the behavior I'm using.
What compiler do you use? I've tried your code Visual Studio 2012 and 2013 and it was compiled without any warnings or errors.
Either way - you should try const_cast instead of static_cast when you are playing with constness
In lieu of a better solution (for now at least), I'm creating a separate overload to accept a pointer-to-non-const-member and then use const_cast to call the originating methods.
As noted, the sample above was for simplicity and clarity's sake, but in actuality I am using several class templates, each inheriting from the other, and so forth. This has resulted in the following rather ugly solution:
// C = containing class (for pointer-to-members, std::nullptr_t if none)
// T = type of data being referenced
template<typename _C, typename _T> struct MakeMemberPointer // STL doesn't provide this??
{
public:
typedef _T _C::* Type;
};
// Note: base-class template has specialization for C == std::nullptr_t
typedef typename std::conditional<std::is_same<C, decltype(nullptr)>::value,
T const* C::*,
T const*
>::type N;
typedef typename std::conditional<std::is_member_pointer<T>::value,
typename MakeMemberPointer<
C,
typename std::add_pointer<
typename std::remove_const<
typename std::remove_reference<
decltype(*(static_cast<C*>(nullptr)->*static_cast<N>(nullptr))) // T const&
>::type // reference removed -> T const
>::type // const removed -> T
>::type // pointer added -> T*
>::Type, // member pointer -> T* C::*
typename std::add_pointer<typename std::remove_const<typename std::remove_pointer<N>::type>::type>::type
>::type NNoConst;
void DoSomething(N t) noexcept
{
}
void DoSomething(NNoConst t) noexcept
{
DoSomething(const_cast<N>(t));
}
The class containing all of this is a const-only class derived from a non-const base class (but used here with const members due to template arguments). Declaring all this inside the class is highly preferable (to me) over having to use const_cast in the calling code, but I still don't see why gcc isn't allowing this conversion implicitly (after all, it's just adding const qualifiers!!).
I'm currently working on cleaning up an API full of function templates, and had a strong desire to write the following code.
template <typename T, typename U, typename V>
void doWork(const T& arg1, const U& arg2, V* optionalArg = 0);
When I invoke this template, I would like to do so as follows.
std::string text("hello");
doWork(100, 20.0, &text);
doWork('a', text); // oops!
doWork<char, std::string, void>('a', text); // to verbose!
Unfortunately, the second invocation doesn't compile since the compiler cannot deduce the type of the optional parameter. This is unfortunate, since I really don't care what the parameter type is, but rather that its value is NULL. Also, I'd like to avoid the route of the third invocation since it hampers readability.
This lead me to try to make the template argument V have a default type, which also doesn't work since you cannot apply a default type to a function template argument (at least using VC++ 9.0).
template <typename T, typename U, typename V = void> // oops!
void doWork(const T& arg1, const U& arg2, V* optionalArg = 0);
My only remaining option is to introduce an overload of doWork that knows nothing of the template argument V.
template <typename T, typename U>
void doWork(const T& arg1, const U& arg2)
{
doWork(arg1, arg2, 0);
}
template <typename T, typename U, typename V>
void doWork(const T& arg1, const U& arg2, V* optionalArg);
Is this the best approach to solving this problem? The only drawback I see is that I could potentially introduce many trivial forwarding functions if a function template contains many parameters that have suitable defaults.
I think that your forwarding function is a perfectly suitable solution, although in your solution, won't you have to explicitly specify the template parameters? (0 is an integer constant that can be coverted to any V* type.) Also doWord vs doWork?
As a general rule, try to avoid optional parameters where they don't have a very strong pay-off.
It might be easier to force clients of you function to just add a , (void*)0 if appriopriate than add to much extra mechanism to support both a two parameter and a three parameter version of the template. It depends on the expected uses, though.
From the client code's point of view, if it doesn't have a third parameter, why does it need to invent one?
So if you aim for usability and readability, I agree with your wrapper method: it makes perfect sense, and the wrapper you wrote is responsible for a decent value of the third parameter you necessitated.
On top of that, it makes it possible to use a different default for different specializations, if needed.
One possibility is to reorder the template arguments, so the optional one comes first.
template <typename V, typename T, typename U>
void doWork(const T& arg1, const U& arg2, V* optionalArg = 0);
doWork<void>('a', text);
Forwarding looks OK too.
But it seems default arguments and templates don't match well, though.