December 23, 2020
On Wednesday, 23 December 2020 at 20:56:26 UTC, jmh530 wrote:
> On Wednesday, 23 December 2020 at 16:25:58 UTC, 9il wrote:
>> [snip]
>> 1.
>> Alias template function parameter resolution
>> https://github.com/dlang/dmd/pull/9778
>>
>> [snip]
>
> I gave some thought to potential alternatives, but this is really the simplest way to think about it.
>
> For instance, I would imagine that something like below would be expected to compile if this is ever resolved.
>
> struct Foo(T) {}
> alias Bar(T) = Foo!T;
> void f(T)(Foo!T x) {}
> void b(T)(Bar!T x) {}
> void main() {
>     auto foo = Foo!int();
>     auto bar = Bar!int();
>     foo.f;
>     foo.b;
>     bar.f;
>     bar.b;
> }
>
> If you instead use template constraints, then you have to rely on helper functions for anything more complicated and you are no longer following DRY. For instance, a function like
> enum bool isBar(T) = is(T == Foo!U, U);
> void fb(T)(T x) if(isBar!T) {}
> will compile (adjusting the calls above), but you are repeating Foo!U.
> Because of the bugs mentioned in other posts, replacing isBar with below will not.
> enum bool isBar(T) = is(T == Bar!U, U);
>
> Given the similarities between template constraints and concepts, something like below could accomplish something similar
> concept Bar(T) = is(T == Foo!U, U);
> but that doesn't help you if you want to also be able to use the template alias, as in
> auto bar = Bar!int();
> This is because Bar(T) in the concept should be passing a Foo!T. You would still need to have the alias for Bar if you want that functionality (and how to name them when they are doing similar things). Abusing C++'s syntax you might have something like
> concept Bar(T) = requires(U)() {
>     Foo!U; //akin to something like typename T::Foo<U>;
> }
> where we would basically be telling the compiler that T has to be a Foo!U, which would mean you would have to use Bar like Bar!U...at least that's the idea. I don't think anything like this would work currently in C++.

I don't have time to dig into what you are trying to do, but you'll be surprised what can be done in C00... but I think the original point is that your example unifies fine with C++ :

template<class T>
struct Foo {
    int f,b;
};

template<class T>
using Bar = Foo<T>;

template<class T>
void f(Foo<T> x) {};

template<class T>
void b(Bar<T> x) {}

int main() {
    auto foo = Foo<int>();
    auto bar = Bar<int>();
    foo.f;
    foo.b;
    bar.f;
    bar.b;
}

December 23, 2020
On Wednesday, 23 December 2020 at 21:37:11 UTC, Ola Fosheim Grøstad wrote:
>     foo.f;
>     foo.b;
>     bar.f;
>     bar.b;
> }

argh, forget that... I am tired... Sorry.




December 23, 2020
On Wednesday, 23 December 2020 at 21:47:32 UTC, Ola Fosheim Grøstad wrote:
> On Wednesday, 23 December 2020 at 21:37:11 UTC, Ola Fosheim Grøstad wrote:
>>     foo.f;
>>     foo.b;
>>     bar.f;
>>     bar.b;
>> }
>
> argh, forget that... I am tired... Sorry.

template<class T>
struct Foo {
};

template<class T>
using Bar = Foo<T>;

template<class T>
void f(Foo<T> x) {};

template<class T>
void b(Bar<T> x) {}

int main() {
    auto foo = Foo<int>();
    auto bar = Bar<int>();
    f(foo);
    b(foo);
    f(bar);
    b(bar);
}

better...
December 23, 2020
The big picture that the DIP suggested was that when stuff like this fails to compile:

  struct Foo(T) {}

  alias Bar(T) = Foo!T;

  void f(T)(Bar!T x) {}

  void main() {
    auto foo = Bar!int();
    f(foo);
  }

Then most programmers would just conclude that the compiler is broken beyond repair and move on to another language. I certainly did so with g++ in the 90s. Such issues are deal breakers for any sane professional programmer, only hobbyists would accept that.

Most people won't ask for help in the forums if the compiler fails on things that look trivial. They will conclude that the type unification in the compiler is unstable.






December 24, 2020
On Wednesday, 23 December 2020 at 20:56:26 UTC, jmh530 wrote:
> doing similar things). Abusing C++'s syntax you might have something like
> concept Bar(T) = requires(U)() {
>     Foo!U; //akin to something like typename T::Foo<U>;
> }
> where we would basically be telling the compiler that T has to be a Foo!U, which would mean you would have to use Bar like Bar!U...at least that's the idea. I don't think anything like this would work currently in C++.

I don't use concepts yet as it is a very new C++ feature. The following code does not work in XCode, although it probably should according to cppreference. So take this with a grain of salt (other variations should be possible):

namespace detail {
  template<template<typename> typename F, class U>
  constexpr void _is_instantiable(F<U> a){}
}

template<class T>
struct Foo{};

template<class T>
concept Fooish = requires(T a){
    detail::_is_instantiable<Foo>(a);
};


December 24, 2020
On Wednesday, 23 December 2020 at 20:56:26 UTC, jmh530 wrote:
> concept Bar(T) = requires(U)() {
>     Foo!U; //akin to something like typename T::Foo<U>;
> }
> where we would basically be telling the compiler that T has to be a Foo!U, which would mean you would have to use Bar like Bar!U...at least that's the idea. I don't think anything like this would work currently in C++.

Non-concept version is more verbose, but yeah, works fine in C++17:

namespace detail {
    template<template<typename> class F, class U>
    static constexpr void _dummy(const F<U> &a);

    template<class T, template<typename> typename F, class=void>
    struct has_outer_template : std::false_type {};

    template<class T, template<typename> typename F>
    struct has_outer_template<T,F,std::void_t<decltype(_dummy<F>(std::declval<T&>()))>>: std::true_type {};
};

template <class T, template<typename> typename F>
inline constexpr bool has_outer_template = detail::has_outer_template<T,F>::value;

template<class T>
struct Foo{};

static_assert(has_outer_template<Foo<int>,Foo>);

December 24, 2020
On Thursday, 24 December 2020 at 11:05:16 UTC, Ola Fosheim Grøstad wrote:
> On Wednesday, 23 December 2020 at 20:56:26 UTC, jmh530 wrote:
>> [...]
>
> Non-concept version is more verbose, but yeah, works fine in C++17:
>
> namespace detail {
>     template<template<typename> class F, class U>
>     static constexpr void _dummy(const F<U> &a);
>
>     template<class T, template<typename> typename F, class=void>
>     struct has_outer_template : std::false_type {};
>
>     template<class T, template<typename> typename F>
>     struct has_outer_template<T,F,std::void_t<decltype(_dummy<F>(std::declval<T&>()))>>: std::true_type {};
> };
>
> template <class T, template<typename> typename F>
> inline constexpr bool has_outer_template = detail::has_outer_template<T,F>::value;
>
> template<class T>
> struct Foo{};
>
> static_assert(has_outer_template<Foo<int>,Foo>);

Thank you for the examples. They make sense.
December 24, 2020
On Wednesday, 23 December 2020 at 18:05:40 UTC, 9il wrote:
> It was a mockery executed by Atila
Read the all comments and didnt saw any mockery
December 24, 2020
On Thursday, 24 December 2020 at 14:08:32 UTC, welkam wrote:
> On Wednesday, 23 December 2020 at 18:05:40 UTC, 9il wrote:
>> It was a mockery executed by Atila
> Read the all comments and didnt saw any mockery

Yes, it wasn't explicit. He didn't write bad words, he did a bad decision. Bad for D.
December 24, 2020
On Thursday, 24 December 2020 at 09:56:50 UTC, Ola Fosheim Grøstad wrote:
> [snip]
>
> I don't use concepts yet as it is a very new C++ feature. The following code does not work in XCode, although it probably should according to cppreference. So take this with a grain of salt (other variations should be possible):
>
> namespace detail {
>   template<template<typename> typename F, class U>
>   constexpr void _is_instantiable(F<U> a){}
> }
>
> template<class T>
> struct Foo{};
>
> template<class T>
> concept Fooish = requires(T a){
>     detail::_is_instantiable<Foo>(a);
> };

That Foo-ish reminds me of something in D like

    static if (__traits(compiles, {
        auto temp = Foo!T.init;
    }))