Given a template, for example foo
:
template<typename... ARGS>
struct foo {};
And two partial specializations for a template bar
:
template<template<typename...> class T , typename... ARGS>
struct bar<T<ARGS...>>
{};
template<typename... ARGS>
struct bar<foo<ARGS...>>
{};
Is not the second partial specialization more specialized than the first and must be instanced instead of the template-template parameter specialization?
I'm currently writting multiple-variable lambda expressions for template meta-programming based on this paper.
As the paper shows, one could develop easily tmp lambda expressions given a Haskell-like let
expression. In my case, I have extended the contents of the paper developing variadic-templates based multiple variable let expressions (Via curryfying multiple nested unary let expressions), and then implementing multiple-variable lambda expressions.
My lambda expression template, tml::multi_lambda
, is defined as follows:
template<typename BODY , typename... VARIABLES>
struct multi_lambda
{
template<typename... ARGS>
using result = tml::eval<tml::multi_let<VARIABLES...,
ARGS...,
BODY
>>;
};
where tml::eval
is a metafunction for evaluating expressions, like Boost::mpl mpl::apply
(See my previous question for more context).
The evaluation function tml::eval
is specialized both for generic functional expressions, and specifically for this lambda expressions. That are the two specializations of the above example.
When I try to evaluate a lambda expressions, like:
using lambda = tml::multi_lambda<_1,_2, f<_1,_2>>; //f is a function,
//_1 _2 are placeholders
using result = tml::eval<lambda,int,int>; //Evaluate lambda with int int as parameters
tml::eval
instantiates the generic template-template specialization (Designed for generic evaluable expressions) instead of the partial specialization for lambdas.
tml::eval
and SSCCEtml::eval
is a metafunction dessigned to evaluate any kind of expression, returning the result. The default implementation is specialized for three cases:
The expression is not a function, is a value only: The result of evaluating such expression is the expression itself:
template<typename E>
struct evaluate_impl<E>
{
using result = E;
};
The expression is a function: The result of the evaluation is the value of the result
member type of the function. The parameters of the function are evaluated too (To take care of nested expressions):
template<template<typename...> class F , typename... ARGS>
struct evaluate_impl<F<ARGS...>> : public F<tml::eval<ARGS>...>
{};
The expression is a function, and more argumments are passed to tml::eval
to evaluate the expression with that custom argumments: The parameters of the expression are ignored and the custom are passed and evaluated:
template<template<typename...> class F , typename... PLACEHOLDERS , typename... ARGS>
struct evaluate_impl<F<PLACEHOLDERS...>,ARGS...> : public F<tml::eval<ARGS>...>
{};
So tml::eval
is just a template alias to ride over the typename ::result
:
template<typename... ARGS>
using eval = typename eval_impl<ARGS...>::result;
Finally, the user could specialize eval_impl
to override that default behaviour, or make corner cases work. For example, my one-variable lambda expressions template, defined as follows:
template<typename VARIABLE , typename VALUE , typename BODY>
struct lambda
{
template<typename ARG>
using result = tml::eval<tml::let<VARIABLE , ARG , BODY>>;
};
specializes eval_impl
to make evaluation of lambda expressions work:
template<typename VARIABLE , typename BODY , typename ARG>
struct evaluate_impl<tml::lambda<VARIABLE,BODY>,ARG>
{
using result = typename tml::lambda<VARIABLE,BODY>::template result<ARG>;
};
The multiple-variable lambda expressions which I have the problem take a similar approach:
template<typename... VARIABLES , typename BODY , typename... ARG>
struct evaluate_impl<tml::multi_lambda<BODY,VARIABLES...>,ARGS...>
{
using result = typename tml::multi_lambda<BODY,VARIABLES...>::template result<ARGS...>;
};
But instead of working (Like the one variable counterpart), tml::eval
instantiates the case three of the default evaluate_impl
implementation, or fails due to ambiguous specializations (Case three vs multi_lambda
specialization).
Here is an SSCCE:
//An example function:
template<typename... ARGS>
struct F
{
using result = std::integral_constant<std::size_t,sizeof...(ARGS)>;
};
//This works fine:
using lambda_1 = tml::lambda<_1,F<_1,_1,_1,_1>>;
using result_1 = tml::eval<lambda_1,int>; //Call the lambda with int as parameter
//This doesn't work:
using lambda_2 = tml::multi_lambda<_1,_2,F<_1,_1,_2,_2>>;
using result_2 = tml::eval<lambda_2,int,int>; //Call the lambda with two int as parameters.
The evaluation of lambda_2
fails with:
functional.hpp:167:76: error: ambiguous class template instantiation for 'struct tml::impl::evaluate_impl<tml::impl::multi_lambda<tml::placeholders::_1, tml::placeholders::_2, f<tml::placeholders::_1, tml::placeholders::_1, tml::placeholders::_2, tml::placeholders::_2> >, int, int>'
using eval = typename impl::evaluate_impl<EXPRESSION , ARGS...>::result;
^
functional.hpp:116:16: error: candidates are: struct tml::impl::evaluate_impl<F<PLACEHOLDERS ...>, ARG, ARGS ...>
struct evaluate_impl<F<PLACEHOLDERS...> , ARG , ARGS...> :
^
In file included from main.cpp:24:0:
lambda.hpp:160:16: error: struct tml::impl::evaluate_impl<tml::impl::multi_lambda<BODY, VARIABLES ...>, ARGS ...>
struct evaluate_impl<multi_lambda<BODY,VARIABLES...>,ARGS...> :
I'm using GCC4.8.2
First of all, you should really learn what an SSCCE really is, especially the "complete" part. Also, short. That said, I tried to create an SSCCE which seems to reproduce your problem, see at the end of my answer. Looking at the error message you receive, it seems that your real code for the third specialization looks more like
template<template<typename...> class F ,
typename... PLACEHOLDERS ,
typename ARG ,
typename... ARGS>
struct evaluate_impl<F<PLACEHOLDERS...>,ARG,ARGS...>
: public F<tml::eval<ARG,ARGS>...>
{};
Note the additional explicit mentioning of ARG
, which seems superfluous and which could cause the ambiguity in your case. If you replace it with
template<template<typename...> class F ,
typename... PLACEHOLDERS ,
typename... ARGS>
struct evaluate_impl<F<PLACEHOLDERS...>,ARGS...>
: public F<tml::eval<ARGS>...>
{};
the problem might just disappear.
And finally, here's an SSCCE that I used to get a similar error than you.
Update: With your SSCCE from the comments below the situation can be resolved simply by disabling the specialization for F
when it is foo
. The condition would look like this:
typename std::enable_if<!std::is_same<F<>,foo<>>::value>::type
or see the complete live example based on your SSCCE. By that, you can probably also add ARG
back as both specializations should be mutually exclusive now.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With