Non-proto objects as terminals - boost

I would like to use instances of a non-proto class as proto terminals
for all purposes. To enable this functionality, I use is_terminal
metafunction and pass it to BOOST_PROTO_DEFINE_OPERATORS().
This actually defines the operators, so the following expression makes
an expression tree, as expected:
non_proto_obj * proto_obj; // creates proto expression tree
However, I cannot do this:
non_proto_obj = proto_obj; // no operator=
non_proto_obj[proto_obj]; // no operator[]
While the opposite does compile:
proto_obj = non_proto_obj;
proto_obj[non_proto_obj];
It seems that my object is not convertible to proto expression.
Is there any workaround for this issue?
(On Coliru)
#include <iostream>
#include <boost/proto/proto.hpp>
#include <boost/mpl/int.hpp>
namespace mpl = boost::mpl;
namespace proto = boost::proto;
using proto::_;
template<typename Expr>
struct my_expression;
struct my_domain : proto::domain<proto::generator<my_expression> >
{};
template<int I> struct placeholder {};
template<typename Expr>
struct my_expression : proto::extends<Expr, my_expression<Expr>, my_domain>
{
explicit my_expression(Expr const &expr = Expr()) :
my_expression::proto_extends(expr)
{}
BOOST_PROTO_EXTENDS_USING_ASSIGN(my_expression<Expr>)
};
const my_expression<proto::terminal<placeholder<1>>::type> _1;
namespace app
{
struct non_proto_type
{};
template <typename T>
struct is_terminal : mpl::false_
{};
template<>
struct is_terminal<non_proto_type> : mpl::true_
{};
BOOST_PROTO_DEFINE_OPERATORS(is_terminal, my_domain)
non_proto_type non_proto;
}
int main()
{
_1 = app::non_proto; // ok, builds temporary proto expression
//app::non_proto = _1; // does not compile! no operator=
_1[app::non_proto]; // ok
//app::non_proto[_1]; // does not compile! no operator[]
(+app::non_proto)[_1]; // ok! applying unary + to make a proto expression first, then operator[] is available
}

There is no work around.
The C++ language places restrictions on some operators. Notably, the indexing (operator[]), assignment and function call operators must be defined as a non-static member function.
This means that there can never be an implicit conversion on the "left-hand-side" operand in an expression of the type lhs[rhs]. End of story.
All EDSL frameworks I know have helper functions to decorate your "literal" expression as a domain expression, e.g. boost::phoenix::val(x) or boost::spirit::x3::as_parser(x).

Related

Recursively unpacking a template pack for a parameter-less function

I'm trying to create a struct template with a variadic template type pack, that can deduct the sum of the size of all types passed in.
Below you find a simplified example, in the real-world context, the size computed is used to create further member objects.
template <typename... Types>
struct OverallSize
{
template <typename FirstType, typename... NextTypes>
static constexpr size_t sizesum() { return sizeof (FirstType) + sizesum<NextTypes...>(); }
template <typename LastType>
static constexpr size_t sizesum() { return sizeof (LastType); }
static constexpr size_t size = sizesum<Types...>();
};
// Should work e.g. like this
auto s = OverallSize<int, float, char>::size; // s will be 9 on x86-64
I'm used to this recursive parameter unpacking approach when it comes to argument lists and assumed this works as well with argument-less functions and explicit template specification. However I get the following error when compiling with clang
Call to 'sizesum' is ambiguous
...
Candidate function [with FirstType = unsigned long, NextTypes = <>]
Candidate function [with LastType = unsigned long]
So it seems as if the last recursion iteration doesn't work here – not sure why the compiler doesn't simply chose the most obvious choice: The one with only one template type – just as it would happen if there was an actual template argument passed to the function.
So, what do I have to do to make this compile and work as desired?
For C++14 you can use SFINAE:
template <
typename FirstType,
typename... NextTypes,
std::enable_if_t<sizeof...(NextTypes) >= 1>* = nullptr >
static constexpr size_t sizesum() {
return sizeof (FirstType) + sizesum<NextTypes...>();
}
this template will be considered only if parameters pack has size >= 1.
Demo

SFINAE expression fails to compile with clang

This looks like an issue in clang (I've already opened a bug here), but I'd like to be sure that I'm not doing a mistake.
Consider the following code:
#include <type_traits>
#include <cstddef>
template<std::size_t N, std::size_t M, std::enable_if_t<not (N>M)>* = nullptr> // (1)
struct S: public S<N+1, M> { };
template<std::size_t N>
struct S<N, N> { };
int main() {
S<0, 1> c{};
}
It fails to compile with the following error:
8 : error: non-type template argument specializes a template parameter with dependent type 'std::enable_if_t M)> *' (aka 'typename enable_if M), void>::type *')
struct S { };
The same code works as expected using the following line instead of (1):
template<std::size_t N, std::size_t M, typename = std::enable_if_t<not (N>M)>>
The SFINAE expression is almost the same. It is based on a specialization of std::enable_if_t and I would expect the same result (success or failure) for both of the examples.
Are my expectations wrong?
Note that GCC works fine in either cases.
I think this is a gcc bug actually, as a result of [temp.class.spec]:
The type of a template parameter corresponding to a specialized
non-type argument shall not be dependent on a parameter of the
specialization. [ Example:
template <class T, T t> struct C {};
template <class T> struct C<T, 1>; // error
template< int X, int (*array_ptr)[X] > class A {};
int array[5];
template< int X > class A<X,&array> { }; // error
—end example ]
In your example, the type of the 3rd template parameter is dependent on a parameter. When you swap it to typename = std::enable_if_t<...>, then this rule no longer applies.
Note: is there any reason to use SFINAE here anyway, as opposed to static_assert-ing?

c++11 std::function like functors incomplete type

I've stumbled upon something I can't get through since last week...
Having this:
template<typename> struct fx;
template<typename R, typename...Args>
struct fx<R(Args...)>
{
virtual R operator()(const Args & ...x) const = 0;
};
and this:
template<typename> struct fx_err;
// I feel here something is wrong, but I can't figure it out.
template<template<typename> class F, typename R, typename... Args>
struct fx_err< F<R(Args...)> > : fx<R(R,Args...)>
{
using fx_type = F<R(Args...)>;
fx_type f;
R operator ()(const R &y, const Args & ...x) const override
{
return y - f(x...);
}
};
and this:
struct example_fun : fx<int(int,int,int)>
{
int operator() (const int &a, const int &b, const int &c) const override
{
return a * b * c;
}
};
when finally I try to use it like:
fx_err<example_fun> example;
int err = example(24,2,3,4);
compiler throws error: 'example has incomplete type'.
Something similar works only if I do not specialize fx_err and use pointer to fx_type functor instead, but then I need to add constructor to grab the pointer itself which is not something I want.
It's very frustrating. What's wrong with this? Is it possible what I'm trying to achieve? Can anybody help?
Thanks in advance.
UPDATE:
here's example code to play around with for those willing to experiment with this example: http://pastebin.com/i3bRF8tB
The problem on line:
fx_err<example_fun> example;
is caused by the fact that example_fun is "passed" to fx_err, which selects the declaration:
template<typename> struct fx_err;
which is an incomplete type.
The specialization you provide:
// I feel here something is wrong, but I can't figure it out.
template<template<typename> class F, typename R, typename... Args>
struct fx_err< F<R(Args...)> > : fx<R(R,Args...)>
{ ... }
cannot be selected, because example_fun is not a template class as required by:
template<typename> class F
Avoid template template parameters if you can. They add more complexity, and less flexibility, than you probably want.
It looks like you're trying to match the form of the fx base class against its derived class. Partial specialization requires exact matches, it won't slice to the base class. And even if it did, this member would be of abstract class type:
using fx_type = F<R(Args...)>;
fx_type f; // same as fx<R(Args...)> which is abstract
The solution is to preserve the derived class, and tell the partial specialization how to find the base. Then the partial specialization can do pattern matching on the base class.
template<typename derived, typename base = typename derived::fx>
struct fx_err;
template<typename derived, template<typename> class F, typename R, typename... Args>
struct fx_err< derived, F<R(Args...)> > : F<R(R,Args...)>
Live solution: http://coliru.stacked-crooked.com/a/870172bcad0a9034
Of course, finding the base class by typename derived::fx sort-of begs the question of what base class template was used. In theory, you could have several templates of the same name, or derived could have a member typedef my_base fx; instead of inheriting from an fx specialization.
More likely, though, you don't need template<typename> class F at all.
template<typename derived, typename base = typename derived::fx>
struct fx_err;
template<typename derived, typename R, typename... Args>
struct fx_err< derived, fx<R(Args...)> > : fx<R(R,Args...)>
fx_err<example_fun> does not match your partial specialization because example_fun is not of the form F<R(Args...)>. It inherits a type of that form, but that's not the same thing.
When selecting specializations for class templates, implicit conversions aren't considered. Therefore example_fun isn't seen as a fx<...> by the compiler when matching the specializations and the primary (undefined) template is chosen over the other specialization.
To solve this you can expose an alias for the base class in the derived class:
struct example_fun : fx<int(int,int,int)>
{
using type = fx<int(int,int,int)>;
};
And now use this alias at the declaration site:
fx_err<example_fun::type> example;
int err = example(24,2,3,4);
You can even use a macro to avoid repeating the base class name:
template<class T> struct tag { using type = T; };
#define BASE_TAG(B) B, public tag<B>
struct example_fun : BASE_TAG(fx<int(int, int, int)>) {
// ...
};
Your basic problem is that template type pattern matching does not work like function overload template pattern matching. Inheritance is ignored, only the type passed in is pattern matched against.
So struct foo: some_template<some_args...> does not match some_template<some_args...> during template type pattern matching for the purpose of figuring out which specialization to use.
This lets us work with types as values in functions:
template<class T>struct tag{using type=T;};
template<class Tag>using type_t=typename Tag::type;
Now function template pattern matching works more like what you seem to be expecting:
template<template<class...>class Z, class...Args>
constexpr tag<Z<Args...>> get_template( Z<Args...>const& ) { return {}; }
takes a single argument, does template function pattern matching and deduction against it. This will look at parents of the type passed in. It tries to match Z<Args...> for some template Z.
It returns a tag<Z<Args...>>, which is a stateless type that just stores the type we need. We can then feed the above through an alias to extract that template expansion:
template<class T>
using get_template_t = type_t<decltype(get_template(std::declval<T>()))>;
which is most of the way there.
Next, we need some SFINAE helper magic:
template<class...>struct voider:tag<void>{};
template<class...Ts>using void_t=type_t<voider<Ts...>>;
std::void_t is C++14, and takes a bunch of types and throws them away, returning void instead. I do it in 2 lines because some compilers fail on the one-line version.
Ok, now we attack fx_err:
template<class,class=void> struct fx_err;
the second class=void lets us do FSINAE work. We start with your
template<template<class...>class F, class R, class...Args>
struct fx_err< F<R(Args...)>, void > : fx<R(R,Args...)>
{
using fx_type = F<R(Args...)>;
fx_type f;
R operator ()(const R &y, const Args & ...x) const override {
return y - f(x...);
}
};
and we also do this:
template<class T>
struct fx_err< T, void_t<get_template_t<T>>> : fx_err<get_template_t<T>>
{};
which I think should work. If it doesn't, we just need to add a test to exclude the direct T<F(Args...)> case from this specialization.

is_enum causing incorrect behavior for SFINAE application?

I have been playing around with SFINAE applied to the "has_member" type of structs as described here.
So I was trying to use some of the features of c++11 to make these solutions simpler. Having some problems with checking for existence of an enum, but I can't seem to locate my logic error here. Code is:
#include<iostream>
template<typename T >
struct has_enum_name
{
private:
// ***** this is the line that isn't working *****
// If U has an enum "name", then I expect is_enum to return true…
// Then I expect enable_if<>::type to be std::true_type…etc. This isn't what happens.
template<typename U> static auto test(int) -> decltype(
std::enable_if<std::is_enum< typename U::name >::value, std::true_type>::type() );
template<typename U> static auto test(...) -> std::false_type;
public:
static constexpr bool value =
!(std::is_same<decltype(test<T>(0)),std::false_type>::value);
static constexpr bool is_enum()
{
return std::is_enum<typename T::name>::value;
}
};
template<typename T >
struct has_enum_name_2
{
private:
template<typename U> static auto test(int) -> decltype(
std::enable_if<true, std::true_type>::type() );
template<typename U> static auto test(...) -> std::false_type;
public:
static constexpr bool value =
!(std::is_same<decltype(test<T>(0)),std::false_type>::value);
};
struct Foo
{
enum class name
{
enum1,
enum2
};
};
int main()
{
std::cout<<"std::is_enum<Foo::name>::value = "<<std::is_enum<Foo::name>::value<<std::endl;
std::cout<<"has_enum_name<Foo>::value = "<<has_enum_name<Foo>::value<<std::endl;
std::cout<<"has_enum_name<Foo>::is_enum() = "<<has_enum_name<Foo>::is_enum()<<std::endl;
std::cout<<"has_enum_name_2<Foo>::value = "<<has_enum_name_2<Foo>::value<<std::endl;
}
Running this using gcc 4.9.2 gives
$ ./a.out
std::is_enum<Foo::name>::value = 1
has_enum_name<Foo>::value = 0
has_enum_name<Foo>::is_enum() = 1
has_enum_name_2<Foo>::value = 1
The first output line verifies that the std::is_enum works correctly for the Foo::name enum.
The second line outputs the results of struct constexpr "has_enum_name::value". I am just trying to use std::enable_if in conjunction with std::is_enum to make the decltype return something…in this case std::true_type(). As you can see, the output returns false…so the line:
template<typename U> static auto test(int) -> decltype(
std::enable_if<std::is_enum< typename U::name >::value, std::true_type>::type() );
isn't working out like i think it should. I think that is_enum should return true, which means that enable_if should return true_type, and decltype should return true_type().
Next output is just a check to see if std::is_enum<> is working correctly in the struct…it is.
Next output is just a copy of the "has_enum_name" struct, but I replaced the is_enum<> in the suspect line with a hard coded "true"…and it works correctly.
So for some reason, it appears that is_enum is not working returning true. Any ideas what I am doing wrong here?
When you encounter a problem like this, let the compiler help you. Remove the (...) overload to force a compilation error, and see what GCC tells you:
test.cc: In instantiation of ‘constexpr const bool has_enum_name<Foo>::value’:
test.cc:51:71: required from here
test.cc:18:33: error: no matching function for call to ‘has_enum_name<Foo>::test(int)’
!(std::is_same<decltype(test<T>(0)),std::false_type>::value);
^
test.cc:18:33: note: candidate is:
test.cc:12:36: note: template<class U> static decltype (std::enable_if<std::is_enum<typename U::name>::value, std::integral_constant<bool, true> >::type()) has_enum_name<T>::test(int) [with U = U; T = Foo]
template<typename U> static auto test(int) -> decltype(
^
test.cc:12:36: note: template argument deduction/substitution failed:
test.cc: In substitution of ‘template<class U> static decltype (std::enable_if<std::is_enum<typename U::name>::value, std::integral_constant<bool, true> >::type()) has_enum_name<T>::test(int) [with U = Foo]’:
test.cc:18:33: required from ‘constexpr const bool has_enum_name<Foo>::value’
test.cc:51:71: required from here
test.cc:13:83: error: dependent-name ‘std::enable_if<std::is_enum<typename T::name>::value, std::integral_constant<bool, true> >::type’ is parsed as a non-type, but instantiation yields a type
std::enable_if<std::is_enum< typename U::name >::value, std::true_type>::type() );
^
test.cc:13:83: note: say ‘typename std::enable_if<std::is_enum<typename T::name>::value, std::integral_constant<bool, true> >::type’ if a type is meant
That's exactly what's wrong: you merely forgot to add typename. T::type() could be valid if type is a non-type: it could just be a function call. That's how the compiler is parsing it.
By the way, decltype(typename T::type()) seems somewhat pointless unless you're specifically trying to check whether the type is default-constructible, and that's not what you're going for here. You can simply use typename T::type directly, like so:
template<typename U> static auto test(int) ->
typename std::enable_if<std::is_enum<typename U::name>::value, std::true_type>::type;
and if you had tried that without the typename, you would've immediately got a useful error message.
Your initialisation of value is also needlessly complicated, since you already know you're dealing with false_type or true_type: both of those have a value member you can use.
static constexpr bool value = decltype(test<T>(0))::value;

Second scope after struct definition

I looked a bit into Eric Nieblers range library https://github.com/ericniebler/range-v3/ and there (/include/range/v3/utility/concepts.hpp, line 36) I found code of the form
constexpr struct valid_expr_t
{
template<typename ...T>
true_ operator()(T &&...) const;
} valid_expr {};
I am confused to the second scope/braces after valid_expr. What is the meaning of the whole construct. Is this even a struct definition? The syntax seems not allowed in C++98. What can go into these second pair of braces?
It's the C++11 uniform initialization syntax, and it simply initializes the valid_expr object.
It's like doing
struct valid_expr_t
{
template<typename ...T>
true_ operator()(T &&...) const;
};
constexpr valid_expr_t valid_expr {};

Resources