Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Can't access conversion function #583

Open
JohelEGP opened this issue Aug 12, 2023 · 4 comments
Open

[BUG] Can't access conversion function #583

JohelEGP opened this issue Aug 12, 2023 · 4 comments
Labels
bug Something isn't working question - further information requested Further information is requested

Comments

@JohelEGP
Copy link
Contributor

Title: Can't access conversion function.

Minimal reproducer (https://cpp2.godbolt.org/z/49od88YbG):

#include <type_traits>
zero: type == std::integral_constant<int, 0>;
main: () -> int = zero().operator int();
// int main() { return zero().operator int(); }
Commands:
cppfront main.cpp2
clang++17 -std=c++23 -stdlib=libc++ -lc++abi -pedantic-errors -Wall -Wextra -Wconversion -Werror=unused-result -I . main.cpp

Expected result: Same as using the commented out Cpp1 main.

Actual result and error:

main.cpp2(3,35): error: ill-formed initializer (at 'int')
main.cpp2(3,1): error: unexpected text at end of Cpp2 code section (at 'main')
main.cpp2(2,0): error: parse failed for section starting here
@JohelEGP JohelEGP added the bug Something isn't working label Aug 12, 2023
@hsutter
Copy link
Owner

hsutter commented Aug 13, 2023

The intent is that all conversions are invoked using as, and I try to avoid different ways to say the same thing.

This works -- does it satisfy your use case?

answer: type == std::integral_constant<int, 42>;

main: () = 
    std::cout << answer() as int;     // prints 42

@hsutter hsutter added the question - further information requested Further information is requested label Aug 13, 2023
@JohelEGP
Copy link
Contributor Author

In my case, as doesn't work.

I'm porting to Cpp2 a concept to check this (https://eel.is/c++draft/meta.rqmts#1.sentence-4):

The member names of the base characteristic shall not be hidden and shall be unambiguously available in the Cpp17UnaryTypeTrait.

So I need to check the existence of that operator precisely.
Not just any conversion.

@JohelEGP
Copy link
Contributor Author

I'd also like to declare conversion operators in Cpp2.
The syntax for declaring them and accessing them by name should be considered together.

For simplicity, Cpp2's operator as can subsume Cpp1's conversion operator.
Looking at https://wg21.link/P2392 §2.3.4, it seems like operator as has to be a template.
For compatibility with Cpp1, Cpp2 could guarantee that a non-template operator as lowers to a conversion operator.
This integration in itself has its own worth.

This is what I'm envisioning:

toggle: @struct type = {
  bool value;
  flip: (inout this) = value = !value;
  operator as: (this) -> bool = value; // Lowers to `operator bool() const { return value; }`.
}
main: () = {
  fullscreen: toggle = (true);
  [[assert: fullscreen.operator as<bool>()]]
}

fullscreen.operator as<bool>() can be equivalent to Cpp2 cpp2::operator_as<bool>(fullscreen),
which you can see working at https://compiler-explorer.com/z/c9fEcoGbe:

#include "https://raw.githubusercontent.com/hsutter/cppfront/main/include/cpp2util.h"

struct A {
  operator bool() const { return true; }
};

struct B {
  template<std::same_as<bool> T> auto operator_as() const -> T { return true; }
};

struct C { };
template<std::same_as<bool> T> auto operator_as(C) -> T { return true; }

namespace cpp2 {
template<class T> auto operator_as(auto&& x) -> decltype(auto)
  requires requires { CPP2_FORWARD(x).operator T(); }
           || requires { CPP2_FORWARD(x).template operator_as<T>(); }
           || requires { operator_as<T>(CPP2_FORWARD(x)); }
{
  if constexpr (requires { CPP2_FORWARD(x).operator T(); }) {
    return CPP2_FORWARD(x).operator T();
  } else if constexpr (requires { CPP2_FORWARD(x).template operator_as<T>(); }) {
    return CPP2_FORWARD(x).template operator_as<T>();
  } else {
    return operator_as<T>(CPP2_FORWARD(x));
  }
}
}

#include <cassert>
int main() {
  assert(cpp2::operator_as<bool>(A{}));
  assert(cpp2::operator_as<bool>(B{}));
  assert(cpp2::operator_as<bool>(C{}));
}

@JohelEGP
Copy link
Contributor Author

For simplicity, Cpp2's operator as can subsume Cpp1's conversion operator.
Looking at https://wg21.link/P2392 §2.3.4, it seems like operator as has to be a template.
For compatibility with Cpp1, Cpp2 could guarantee that a non-template operator as lowers to a conversion operator.
This integration in itself has its own worth.

Authoring an operator as and being able to invoke it without an as operation can be confusing.
Maybe we should just take the hit and also have conversion operators in Cpp2, which the built-in as can invoke.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working question - further information requested Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants