#include <MySyntax.hpp>
...
//let name1 = object;
//
//let name2 = object[ othervar1 , othervar2 , values val1, val2, val3... ];
let o3 = object [ values 1, "2", true, -3.14 ];
std::cout << o3; // prints: object [ “0”:1 , “1”:“2” , “2”:true , “3”:-3.14 ]
I'm looking to make this in <MySyntax.hpp> with c 11.
I am thinking of let
being a superclass of object
to achieve the initialization (just my first thought).
Also operator overload the []
and <<
on object
.
But where i have no idea is the value
part.
In case it's not clear, anything to the right of value
is put in a collection, with string number indexing (std::Map maybe?). Values can be of ANY type( Also no idea on this, templates come to mind tho).
Any discussion , link's to resources , tips anything. Just looking to learn the amazing extensibility of C !
EDIT::
The key word value
is required. Object will also be able to take this kind of values *see code block example again. Didn't include this at the start because it isn't my original question. I only added it to emphasize the use of values
.
CodePudding user response:
You can use std::tuple
to store various types and print it by overloading operator<<
, and support this syntax by overloading C 23 multidimensional subscript operator.
Something like this:
#include<tuple>
#include<iostream>
template<class... Args>
using let = std::tuple<Args...>;
struct {
template<class... Args>
constexpr auto operator[](Args&&... args) const {
return std::tuple(std::forward<Args>(args)...);
}
} object;
template<class... Args>
auto& operator<<(std::ostream& os, const std::tuple<Args...>& t) {
return std::apply([&os, i = 0](auto& first, auto&... rest) mutable -> auto& {
os << std::boolalpha << "[" << i << ":" << first;
((os << ", " << i << ":" << rest), ...);
return os << "]";
}, t);
}
int main() {
let o = object[1, "2", true, -3.14];
std::cout << o;
}
CodePudding user response:
I think you are better of sticking to what the standard library already offers.
- you will be reusing tested code
- other people will find your code easier to read.
- no need to let C look like python, javascript (or any other language) since languages have totally different philosophies anyway.
Your object can be represented by std::tuple and then code would become this :
#include <iostream>
#include <string_view>
#include <tuple>
//-------------------------------------------------------------------------------------------------
// MySyntax.hpp
// helper function to put a heteroganous list of types into one datastructure
template<typename... args_t>
auto object(args_t&&... args)
{
std::tuple<args_t...> obj{ std::forward<args_t>(args)... };
return obj;
}
// convert function for pretty printing
// normally convert to output type does nothing
template<typename type_t>
const type_t& convert(const type_t& value)
{
return value;
}
// booleans should be outputed as text
std::string_view convert(const bool value)
{
return value ? "true" : "false";
}
// output a tuple to stream
template<class type_t, size_t... index>
void output(std::ostream& os, const type_t& object, std::index_sequence<index...>)
{
os << "[";
// fold expression (so there is no need to create a recursive template function)
(..., (os << (index == 0 ? "" : ", ") << "\"" << index << "\":" << convert(std::get<index>(object))));
os << "]\n";
}
// overload stream operator for tuples
template<typename... args_t>
std::ostream& operator<<(std::ostream& os, const std::tuple<args_t...>& object)
{
output(os, object, std::make_index_sequence<sizeof...(args_t)>());
return os;
}
//-------------------------------------------------------------------------------------------------
// #include <MySyntax.hpp>
int main()
{
// use auto instead of let
auto o3 = object(1, 2.0, true, "hello");
std::cout << "object " << o3;
return 0;
}