Is there a way to compare the result of decltype in C++11?
In other words, why is this code invalid:
template<typename T, typename U>
void func(T& t, U& u) {
if(decltype(t) == decltype(u)) {
// Some optimised version for this case
} else {
// A more general case for differing types
}
}
I know that in some cases this particular problem can be solved by partial template specialisation; my question is about comparison of decltypes.
Edit: The question came up in the course of trying to provide defaults for free functions through SFINAE. Perhaps a better question would have been why this is invalid:
template<bool B>
bool SomeFunction() { ... }
template<typename T, typename U>
bool SomeFunctionWrapper(T& t, U& u) {
SomeFunction<decltype(t) == decltype(u)>();
}
I've since found another solution (that doesn't involve templates at all) but at one stage I tried this:
// If it exists, the free function is defined as
// bool AFreeFunction();
typedef struct { char } undefined;
template<typename T = void>
undefined AFreeFunction();
template<bool B>
bool AFreeFunctionWrapper_() {
return false;
}
template<>
bool AFreeFunctionWrapper_<false>() {
return AFreeFunction();
}
bool AFreeFunctionWrapper() {
return AFreeFunctionWrapper_<decltype(AFreeFunction()) == decltype(undefined)>();
}
I eventually got a variant of this strategy working with GCC 4.6, but then discovered that default template arguments are not allowed for template functions in MSVC, even in the 2012 RC. So the eventual solution looks like this:
class AFreeFunction {
public:
operator bool() { return false; }
};
If the function is defined, it gets called. If it's not, it is instead interpreted as a constructor for the class, which is then implicitly cast to bool.
You normally solve this problem through tag dispatching. Also, you already have the "declared type" of t and u - T& and U&, respectively. To compare types for equality, you can use std::is_same. However, overload resolution already solves this problem for you:
template<class T>
void f(T& v1, T& v2){ ... } // #1
template<class T, class U>
void f(T& t, U& u){ ... } // #2
#1 is more specialized than #2 if both arguments to f are of the same type. If you, for whatever reason, insist on solving this through manual type comparision, here's how it would look applying the before mentioned points:
#include <type_traits>
namespace detail{
template<class T, class U>
void f(T& t, U& u, std::true_type){ ... } // #1
template<class T, class U>
void f(T& t, U& u, std::false_type){ ... } // #2
} // detail::
template<class T, class U>
void f(T& t, U& u){
detail::f(t, u, std::is_same<T,U>()); // tag dispatching
}
std::is_same will derive from std::true_type if both types are the same, and from std::false_type if not.
Why is it invalid? The result of a decltype is, well, a type. So it's saying something like
if (int == int)
which the language obviously doesn't allow.
You'll need to separate the two parts of the function and put the specialized part inside a function in a specialized class, and forward the call there. It's painful.
Or, you could use typeid or run-time type information, if your implementation implements it correctly, although that will defer everything to when the program runs (which allows for fewer optimizations).
You can do this using SFINAE (std::enable_if):
template<typename T, typename U>
typename std::enable_if<std::is_same<T, U>::value, void>::type func(T& t, U& u) {
std::cout << "same\n";
}
template<typename T, typename U>
typename std::enable_if<!std::is_same<T, U>::value, void>::type func(T& t, U& u) {
std::cout << "different\n";
}
As Mehrdad says, decltype(t) and decltype(u) are types (T & and U & respectively), not values, so cannot be compared at value-expression level but must be compared at meta-expression (template) level.
Related
How can I tell the compiler that U is equivalent to either std::vector<T> or T?
template<typename T, typename U> std::vector<T> foo(T t, U){return std::vector<T>{};}
I'm not sure if this is better or worse than your proposed solution, but you can try template specialization, which is similar to function overloading function overloading.
This would look like this
// Generic function
// UPDATE: you can ignore this function altogether and use the two overloads below
template<typename T, typename U> std::vector<T> foo(T t, U u) { // Do something}
// First specialization for the case of U == T
// UPDATE: this is an *overload*, not a specialization
template<typename T> std::vector<T> foo(T t, T u) { // Do something}
// Second specialization for the case of U == std::vector<T>
// UPDATE: this is an *overload*, not a specialization
template<typename T> std::vector<T> foo(T t, std::vector<T> u) { // Do something}
A possible downside of this approach is the possibility of repeating code, which violates the DRY principle.
As such, if your objective is to simply constraint your arguments without needing to change the function definition, then this answer may be better suited for such application.
Update: As #HolyBlackCat commented, my example was of overloading, and not of template specialization. I updated the text accordingly.
I would disable type deduction (by using depending type) on second argument and provided two overloads.
namespace me {
// c++20 has this, so putting that in own namespace to cover older standards
template<typename T>
strut identity {
using type = T;
};
template<typename T>
using identity_t = typename identityT<>::type;
}
template<typename T>
std::vector<T> foo(T t, const std::vector<me::indentity_t<T>>& v) {
auto copy = v;
copy.push_back(t);
return copy;
}
template<typename T>
std::vector<T> foo(T t, me::indentity_t<T> v) {
return { v, t };
}
I found a solution by myself.
It seems could be achieved by std::enable_if. Is there any better way?
#include <iostream>
#include <vector>
template<typename T, typename U, typename = typename std::enable_if<
std::is_same< T, U >::value || std::is_same<std::vector<T>, U>::value>::type>
std::vector<int> foo()
{
std::cout << "on the move!\n";
return {};
}
int main()
{
foo<int, int>();
foo<int, std::vector<int>>();
//foo<int, float>(); //does not compile, in expectation.
}
A better/harder example:
#include <iostream>
#include <vector>
#include <functional>
template<typename T, typename U, typename = typename std::enable_if<
std::is_same< T, U >::value || std::is_same<std::vector<T>, U>::value>::type>
void foo(std::function<U(void)> func)
{
std::cout << "on the move!\n";
}
int main()
{
foo<int>(std::function<int(void)>());
foo<int>(std::function<std::vector<int>(void)>());
//foo<int>(std::function<float(void)>()); //does not compile, in expectation.
}
Suppose I have to following function:
template <typename Op, typename T> T foo(Op op) { }
Op is assumed to have the following method:
T Op::operator()(T&);
(this is a simple case; actually it might have more parameters but their types are known to me).
Now, I want to set a default for the T parameter. The problem is, in order to faux-invoke it (e.g. as in std::result_of<Op::operator()(int&)> I need to have the type of the parameter - which is exactly the type I'm missing.
Is it possible to determine T from Op? So that I may, for example, call:
foo( [](int& x){ return x++; } );
I'm interested in a C++11 solution; if you need a later-standard-version capability, that's also interesting (especially the explanation of why that is).
Note: If Op has multiple compatible operator()'s taking references to different types, I'm ok with having to specifyT` myself, of course - but the compilation should pass when I do that.
If the function object has exactly one signature, you can discover that signature by decltype(&T::operator()) and infer from that:
template<class T> struct X : X<decltype(&T::operator())> {}; // #1
template<class T> struct X<T(T&) const> { using type = T; }; // #2
template<class C, class M> struct X<M (C::*)> : X<M> {}; // #3
// add more specializations for mutable lambdas etc. - see example
template <typename Op, typename T = typename X<Op>::type>
T foo(Op op) { /* ... */ }
Example (C++11).
This is a series of type transformations, expressed as partial template specializations. From a lambda with anonymous type <lambda>, we extract its function call operator type at #1 giving a member function pointer type such as int (<lambda>::*)(int&) const, which matches #3 allowing us to discard the class type giving an abominable function type int(int&) const, which matches #2 allowing us to extract the argument and return type, exposed as X::type which is visible to the original instantiation of X via inheritance. Using partial specializations of the same template for different type computations is a code-golf trick and you might want to avoid it (and use more expressive names) in production code.
If on the other hand the function object has more than one signature (template parameters, default parameters, overloaded, hand-crafted function objects, etc.) then this will not work; you will need to wait for stronger forms of reflection to enter the language.
The existence of template functions shows the question is impossible to answer in general:
struct post_increment
{
template<typename T>
T operator()(T& t) const
{
return t++;
}
};
foo(post_increment{});
// or in C++14: foo([](auto& t) { return t++; });
The result of a function foo taking a mapping T& to T for some set of types T is itself polymorphic. In some cases, this is expressible even in C++11:
template<typename Op>
struct foo_result_t
{
template<typename T>
operator T() const
{
T t {};
op(t);
return t;
}
Op op;
};
template <typename Op>
foo_result_t<Op> foo(Op op)
{
return {op};
}
int i = foo(post_increment{}); // use it with an int
Another solution in case of exactly one signature.
Another... well... almost the same ecatmur's solution but based on a template function, to deduce the types, instead of a template class.
All you need is a declared function two declared functions that deduce the types (and return the same return type of the operator(); you can develop also another function to return, by example, std::tuple<Args...>, if you needs to extract the Args... types)
template <typename T, typename R, typename ... Args>
R deducer (R(T::*)(Args...) const);
template <typename T, typename R, typename ... Args>
R deducer (R(T::*)(Args...));
and a using (a little decltype() delirium) to extract the R type
template <typename T>
using RetType = decltype(deducer(std::declval<decltype(&T::operator())>()));
The following is a full C++11 example
#include <utility>
struct A
{
long operator() (int, char, short)
{ return 0l; }
};
template <typename T, typename R, typename ... Args>
R deducer (R(T::*)(Args...) const);
template <typename T, typename R, typename ... Args>
R deducer (R(T::*)(Args...));
template <typename T>
using RetType = decltype(deducer(std::declval<decltype(&T::operator())>()));
int main ()
{
auto f = [](int& x) { return x++; };
static_assert( std::is_same<RetType<A>, long>::value, "!" );
static_assert( std::is_same<RetType<decltype(f)>, int>::value, "!" );
}
If you wont to manage also volatile operators, you have to add other two deducer()
template <typename T, typename R, typename ... Args>
R deducer (R(T::*)(Args...) volatile const);
template <typename T, typename R, typename ... Args>
R deducer (R(T::*)(Args...) volatile);
I'm trying to select at compile time between different template implementations depending on whether or not the argument implements a particular function. This is a common question (see this S.O. question and this example referenced by this article. The common answer is "use expression SFINAE".
Most of the examples show how expression SFINAE can be used to select based on the presence of a zero-argument function. I've tried to adapt these to my 1-argument use case by using declval (loosely based off of this example), but I cannot seem to get it to work.
I'm sure I'm doing something wrong in the example below, but I can't figure out what it is. The example is trying to define two versions of a template bool Util::Container::Contains(container, value) which will use the container's built-in find(value) method if it exists, and otherwise fall back to a linear search using std::find(...)
Please note: I know I can make this work by just overloading Contains() for unordered_map, unordered_set, etc., but instead I'd like to figure out this pattern-based approach so that it will automatically delegate to any container's find(value) without requiring an overload to be added.
#include <unordered_set>
#include <unordered_map>
#include <vector>
#include <string>
namespace Util::Container {
namespace Detail
{
template <typename T>
class HasFindMethod
{
private:
typedef char YesType[1];
typedef char NoType[2];
// This is how the examples show it being done for a 0-arg function
//template <typename C> static YesType& Test(decltype(&C::find));
// Here's my attempt to make it match a 1-arg function
template <typename C> static YesType&
Test(decltype(std::declval<C>().find(std::declval<const C::value_type&>())));
template <typename C> static NoType& Test(...);
public:
enum { value = sizeof(Test<T>(0)) == sizeof(YesType) };
};
}
// Fallback: uses std::find() to do the lookup if no type-specific T::find(value) exists
template<typename T>
bool Contains(const T& in_container, const typename T::value_type& in_item)
{
const auto& result = std::find(in_container.cbegin(), in_container.cend(), in_item);
return (result != in_container.cend());
}
// Preferred: use T::find() to do the lookup if possible
template<typename T>
inline typename std::enable_if<Detail::HasFindMethod<T>::value, bool>::type
Contains(const T& in_container, const typename T::value_type& in_item)
{
return (in_container.find(in_item) != in_container.end());
}
}
int main()
{
const std::vector<int> v { 1, 2, 3 };
const std::unordered_map<int, std::string> m { {1,"1" }, {2,"2"} };
const std::unordered_set<std::string> s { "1" , "2" };
// These should use the std::find()-based version of Contains() since vector and unordered_map
// have no find(value_type) method. And they do.
const bool r_v = Util::Container::Contains(v, 2);
const bool r_m = Util::Container::Contains(m, { 2, "2" });
// !!!!!!
//
// This should use the T::find(value_type)-based version of Contains() since
// unordered_set has a find(value_type) method.
//
// But it doesn't --- that's the issue I'm trying to solve.
//
const bool r_s = Util::Container::Contains(s, "2");
}
If anyone can show me how to fix this, I'd very much appreciate it.
FWIW, I'm attempting to implement this in Visual Studio 2017 v15.8
An easy way with decltype is
template<typename C, typename V>
auto Contains(const C& c, const V& value)
-> decltype(std::find(c.cbegin(), c.cend(), value) != c.cend())
{
return std::find(c.cbegin(), c.cend(), value) != c.cend();
}
template <typename C, typename Key>
auto Contains(const C& c, const Key& key)
-> decltype(c.find(key) != c.end())
{
return c.find(key) != c.end();
}
but then when both function are possible you would have ambiguous call.
So just add extra parameter to prioritize the overload:
struct low_priority {};
struct high_priority : low_priority {};
template<typename C, typename V>
auto ContainsImpl(low_priority, const C& c, const V& value)
-> decltype(std::find(c.cbegin(), c.cend(), value) != c.cend())
{
return std::find(c.cbegin(), c.cend(), value) != c.cend();
}
template <typename C, typename Key>
auto ContainsImpl(high_priority, const C& c, const Key& key)
-> decltype(c.find(key) != c.end())
{
return c.find(key) != c.end();
}
template <typename C, typename T>
auto Contains(const C& c, const T& t)
-> decltype(ContainsImpl(high_priority{}, c, t))
{
return ContainsImpl(high_priority{}, c, t);
}
Now about your version, you have several issues
The last one:
// Expected Fallback: uses std::find() to do the lookup if no type-specific T::find(value) exists
template<typename T>
bool Contains(const T&, const typename T::value_type&);
// Expected Preferred: use T::find() to do the lookup if possible
template<typename T>
typename std::enable_if<Detail::HasFindMethod<T>::value, bool>::type
Contains(const T&, const typename T::value_type&);
SFINAE allows to discard overload, but not to prioritize them.
You have to use priority, as shown above, or create exclusive set of overload:
template<typename T>
typename std::enable_if<!Detail::HasFindMethod<T>::value, bool>::type
Contains(const T&, const typename T::value_type&);
template<typename T>
typename std::enable_if<Detail::HasFindMethod<T>::value, bool>::type
Contains(const T&, const typename T::value_type&);
In addition to that, as mentioned in comment map family would use key_type and not value_type.
Then your detection code is buggy,
// This is how the examples show it being done for a 0-arg function
//template static YesType& Test(decltype(&C::find));
No, this detects if C has a method find (without overload).
template <typename C> static YesType&
Test(decltype(std::declval<C>().find(std::declval<const C::value_type&>())));
Here, you use SFINAE, but final type would be the (const_)iterator, and Test<C>(0) won't take that overload (unless iterator can be build from 0 which is not the regular case). Adding extra * is a possibility, then you have pointer on iterator which might be initialized by 0.
Else you might use code provided in your provided link:
namespace detail{
template<class T, typename ... Args>
static auto test_find(int)
-> sfinae_true<decltype(std::declval<T>().find(std::declval<const Arg&>()...))>;
template<class, class ...>
static auto test_find(long) -> std::false_type;
} // detail::
template<class C, typename ... Args>
struct has_find : decltype(detail::test_find<T, Args...>(0)){};
// int has higher priority than long for overload resolution
and then use your traits with std::enable_if has_find<Container, Key>::value.
The immediate problem is that the argument you are passing to Test is not compatible with the YesType version.
For example, Detail::HasFindMethod<std::unordered_set<int>> will result in the following two Test signatures (because find would return an iterator):
static YesType& Test(std::unordered_set<int>::iterator);
static NoType& Test(...);
You try to call Test with the argument 0, which is not convertible to iterator. Hence, the second one is picked.
As a solution, use a pointer:
template <typename C> static YesType&
Test(decltype(std::declval<C>().find(std::declval<const C::value_type&>()))*);
// ^
Then do the check with a nullptr argument:
enum { value = sizeof(Test<T>(nullptr)) == sizeof(YesType) };
Now we would have ambiguity (the Test(...) would also match), so we can make that one a worse match:
template <typename C, class ... Args> static NoType& Test(void*, Args...);
As shown in the other answers, this is still a comparatively convoluted solution (and there are more issues that prevent it from working in your instance, such as ambiguity between the overloads when the enable_if does work). Just explaining the particular stopper in your attempt here.
A simpler (in my opinion) and more readable solution can be achieved using void_t utility:
template <typename T, typename Dummy = void>
struct has_member_find : std::false_type { };
template <typename T>
struct has_member_find<T,
std::void_t<decltype(std::declval<T>().find(std::declval<typename T::value_type &>()))>>
: std::true_type { };
template<typename T>
std::enable_if_t<!has_member_find<T>::value, bool>
Contains(const T& in_container, const typename T::value_type& in_item)
{
const auto& result = std::find(in_container.cbegin(), in_container.cend(), in_item);
return (result != in_container.cend());
}
template<typename T>
std::enable_if_t<has_member_find<T>::value, bool>
Contains(const T& in_container, const typename T::value_type& in_item)
{
return (in_container.find(in_item) != in_container.end());
}
Note that void_t is only available since C++17, however it you don't have a full C++17 support you can define it yourself since it's definition is ridiculously simple:
template< class... >
using void_t = void;
You can learn more about this utility and the pattern it introduces in this paper.
This question already has answers here:
Find out whether a C++ object is callable
(8 answers)
Closed 7 years ago.
I use the following way, presented in a stackoverflow answer to determine whether a type is callable or not:
template <typename T>
struct is_callable
{
typedef char (& yes)[1];
typedef char (& no)[2];
// we need a template here to enable SFINAE
template <typename U>
static yes deduce(char (*)[sizeof(&U::operator())]);
// fallback
template <typename> static no deduce(...);
static bool constexpr value = std::is_function<T>::value || (sizeof(deduce<T>(0)) == sizeof(yes));
};
However it fails when a class has more than one overload of operator():
#include <iostream>
template <typename T>
class A
{
T operator()();
T operator()(T a);
T operator()(T a, T b);
};
std::cout << is_callable<A<int>>::value; // false
Is it possible to determine whether a type has any variant (templated or not, one or multiple) of overloaded operator()?
First of all you need to declare A as a full type (A<int> for example).
It's not relyable to check if an object is invokeable or not just through unwrapping and comparing it's operator() because it will fail on templated or overloaded functors.
Im using the following piece of code
to detect if an object is callable with a given function signature (ReturnType(Arguments...))
This works also for overloaded or templated operator()'s since the code tries to invoke the object with the given parameters
instead of comparing the signature of it's unwrapped operator().
As small addition the object can also be checked if it is invokeable from a const, volatile or rvalue context.
#include <type_traits>
template<typename Fn>
struct impl_is_callable_with_qualifiers;
template<typename ReturnType, typename... Args>
struct impl_is_callable_with_qualifiers<ReturnType(Args...)>
{
template<typename T>
static auto test(int)
-> typename std::is_convertible<
decltype(std::declval<T>()(std::declval<Args>()...)),
ReturnType
>;
template<typename T>
static auto test(...)
-> std::false_type;
};
template<bool Condition, typename T>
using add_const_if_t = typename std::conditional<
Condition,
typename std::add_const<T>::type,
T
>::type;
template<bool Condition, typename T>
using add_volatile_if_t = typename std::conditional<
Condition,
typename std::add_volatile<T>::type,
T
>::type;
template<bool Condition, typename T>
using add_lvalue_if_t = typename std::conditional<
Condition,
typename std::add_lvalue_reference<T>::type,
T
>::type;
template<typename T, typename Fn, bool Const, bool Volatile, bool RValue>
using is_callable_with_qualifiers = decltype(impl_is_callable_with_qualifiers<Fn>::template test<
add_lvalue_if_t<!RValue,
add_volatile_if_t<Volatile,
add_const_if_t<Const,
typename std::decay<T>::type>>>
>(0));
It is not possible to determine whether a type has any variant of overloaded operator(),
however you can test for a specific type or perform tests for multiple types to detect "possible" templates.
An example which covers the code from your question would be:
#include <iostream>
template<typename T>
class A
{
public:
A() = default;
T operator()() { return T(); }
T operator()(T a) { return T(); }
T operator()(T a, T b) { return T(); }
};
template <typename TheClass, typename T>
using is_callable = is_callable_with_qualifiers<TheClass, T(T), false, false, false>;
int main()
{
std::cout << is_callable<A<int>, int>::value; // true
}
Demo
If you just need to check if smth is callable - try to call it and see what happens:
template <typename T, typename RetType = decltype(std::declval<T>()())>
constexpr bool check_is_callable(int)
{
return true;
}
template <typename>
constexpr bool check_is_callable(...)
{
return false;
}
template <typename T>
constexpr bool is_callable()
{
return check_is_callable<T>(0);
}
Here std::declval<T>() is getting the object of T type, std::declval<T>()() is attempt to call the object of T type, and if it succeeds, RetType = decltype(std::declval<T>()()) gets the return type of call. If it does not, SFIANE lets drop to the other function overload.
I will pass "stack" and "queue" as template type in following codes.
Knowing that .front() and .top() is not the common function between "queue" and "stack", I use "if" to check.
But it still couldn't compile. (error C2039: 'top' is not the member of std::queue<_Ty>)
Is there any way to solve this problem?
template<typename T>
void push_pop(string *str, T *containers){
string s = typeid(containers).name();
if(s[11]=='q'){
str->push_back(containers->front()); containers->pop();
}else{
str->push_back(containers->top()); containers->pop();
}
}
I know I could use function overloading but I want to solve this using template.
Thanks for the answer!
The problem is that the compiler has to compile both branches of the check, and it cannot compile container.top() for a queue nor container.front() for a stack.
You have to implement separate function templates for std::queue and std::stack:
template<typename V, typename C>
void push_pop(std::string &str, std::stack<V, C> &container) {
str.push_back(container.top());
container.pop();
}
template<typename V, typename C>
void push_pop(std::string &str, std::queue<V, C> &container) {
str.push_back(container.front());
container.pop();
}
It is possible (and I would recommend it) to do this for only the relevant parts:
template<typename V, typename C>
V const &first_element(std::stack<V, C> const &container) {
return container.top();
}
template<typename V, typename C>
V const &first_element(std::queue<V, C> const &container) {
return container.front();
}
template<typename T>
void push_pop(std::string &str, T &container) {
str.push_back(first_element(container));
container.pop();
}
(untested) - I use a macro like the following:
#define FUNC_TEST(func) \
template<typename T> \
struct has_##func \
{ \
template <typename _1> static std::true_type test(decltype(&_1::func)*); \
template <typename > static std::false_type test(...); \
static const bool value = decltype(test<T>(0))::value; \
}
Then, for all the functions I need to test for, I would use the macro to generate the test code, for example:
FUNC_TEST(top);
FUNC_TEST(front);
Then, I would define several helper functions to handle the actual push back:
// If the type supports top(), then the first variant is enabled and selected
template <typename F>
inline enable_fn<has_top<F>, void> use_top(F* o, std::string* dest)
{ dest->push_back(o->top()); }
template <typename F>
inline disable_fn<has_top<F>, void> use_top(F*, std::string*)
{ }
// If the type supports front(), the first variant is selected from below automatically
template <typename F>
inline enable_fn<has_front<F>> use_front(F* o, std::string* dest)
{ dest->push_back(o->front()); }
template <typename F>
inline disable_fn<has_front<F>> use_front(F*, std::string*)
{ }
When calling, simply call both variants, and the compiler will select the appropriate action based on the SFINAE test.
template<typename T>
void push_pop(string *str, T *container){
use_top(container, str);
use_front(container, str);
container->pop();
}
It looks like we're calling both top() and front(), but depending on whether the container supports top() or front() one or the other function call will be compiled out. If the type T supports both front() and top(), it's a little problematic, but I'll leave that as an exercise for you to fix...
(NOTE: you'll need enable_fn which looks something like:
template <typename T>
using type_of = typename T::type;
template <typename C, typename R = void>
using enable_fn = type_of<std::enable_if<C::value, R>>;
I'll leave disable_fn as an exercise for you...
Problem of your code is that you are trying to make run-time check which results in requirement to container class provide both top() and front().
One approach to solve this is, as #Wintermute suggests, to use template specialization.
If you want more fancy and generic way, you can use SFINAE approach, which in combination with C++11 gives clean and nice looking code. Assuming we have only two possible kinds of containers - with either front() or top() method provided (adding new kinds of functions is pretty easy):
template<typename container>
auto get_from_container(container* c, int) -> decltype(std::declval<container>().front(), typename container::value_type()) {
return c->front();
}
template<typename container>
typename container::value_type get_from_container(container* c, long) {
return c->top();
}
template<typename T>
void push_pop(string *str, T *containers){
str->push_back(get_from_container(containers, 0)); containers->pop();
}
Notice second type argument in get_from_container - it is required to shadow "default" implementation with top() method (as described here)