0

I am playing with generic lambda in C++1y and I often confused by don't know what is the type of auto variable/parameter. Is any good way to find it out?

Currently I am using typeid(decltype(arg)).name()) but it is not very useful. @encode gives a slightly better result but still hard to decipher it

example:

auto f = [](auto && a, auto b) {
    std::cout << std::endl;
    std::cout << typeid(decltype(a)).name() << std::endl << @encode(decltype(a)) << std::endl;
    std::cout << typeid(decltype(b)).name() << std::endl << @encode(decltype(b)) << std::endl;
};

int i = 1;
f(i, i);
f(1, 1);
f(std::make_unique<int>(2), std::make_unique<int>(2));
auto const ptr = std::make_unique<int>();
f(ptr, nullptr);

output

i  // it does not tell me it is reference
^i // ^ means pointer, but it is actually reference, kinda pointer though
i
i

i
^i
i
i

NSt3__110unique_ptrIiNS_14default_deleteIiEEEE
^{unique_ptr<int, std::__1::default_delete<int> >={__compressed_pair<int *, std::__1::default_delete<int> >=^i}}
NSt3__110unique_ptrIiNS_14default_deleteIiEEEE
{unique_ptr<int, std::__1::default_delete<int> >={__compressed_pair<int *, std::__1::default_delete<int> >=^i}}

NSt3__110unique_ptrIiNS_14default_deleteIiEEEE
r^{unique_ptr<int, std::__1::default_delete<int> >={__compressed_pair<int *, std::__1::default_delete<int> >=^i}}
Dn
*

I mainly want is to know that is the parameter a lvalue ref/rvalue ref/passed by value etc.

and I am using Xcode 5.1.1

Bryan Chen
  • 45,816
  • 18
  • 112
  • 143
  • This could help: http://stackoverflow.com/questions/1488186/stringifying-template-arguments – zch Apr 24 '14 at 10:41
  • 2
    `@encode` is not C++. Are you writing C++, or Objective-C++? `^ means pointer, but it is actually reference, kinda pointer though` No, it means something _quite_ different. – Lightness Races in Orbit Apr 24 '14 at 10:41
  • Have you tried using the type-traits to get information about the type? Like for example [`std::is_reference`](http://en.cppreference.com/w/cpp/types/is_reference)? See [this reference](http://en.cppreference.com/w/cpp/types) for a full list. – Some programmer dude Apr 24 '14 at 10:42
  • @LightnessRacesinOrbit yes it is Objective-C++. `.mm` file. but from my experience, `@encode` works for most of the C++ class (not for very complex templates class) – Bryan Chen Apr 24 '14 at 10:44
  • 2
    @BryanChen: They are two different languages, so your question is tagged incorrectly. Please fix. – Lightness Races in Orbit Apr 24 '14 at 10:45
  • @JoachimPileborg yes it will be my last resort – Bryan Chen Apr 24 '14 at 10:45
  • @LightnessRacesinOrbit I actually want C++ answer. Because ObjC++ is superset of C++ so I can use it for ObjC++ code. – Bryan Chen Apr 24 '14 at 10:46
  • 2
    However, doing checks of the type is often a sign of bad design. You might want to check your design. Also, you might want to read [about the XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem), because you have a solution you want to use but need help implementing it but you're not telling us what kind of problem you actually want to solve with your solution. There may be other, even better, solutions to your original problem. – Some programmer dude Apr 24 '14 at 10:48
  • 2
    @JoachimPileborg I don't have original problem. I am learning how generic lambda works. I can read standard but I want to learn it from code. – Bryan Chen Apr 24 '14 at 10:50
  • This is more YX. Or maybe Rx. Would you believe XYZ? – Yakk - Adam Nevraumont Apr 24 '14 at 12:51

3 Answers3

4

Use GCC’s __cxa_demangle function:

std::string demangled(std::string const& sym) {
    std::unique_ptr<char, void(*)(void*)>
        name{abi::__cxa_demangle(sym.c_str(), nullptr, nullptr, nullptr), std::free};
    return {name.get()};
}

auto f = [](auto && a, auto b) {
    std::cout << demangled(typeid(decltype(a)).name()) << '\n';
    std::cout << demangled(typeid(decltype(b)).name()) << '\n';
};
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • thanks. it is very useful to decipher `NSt3__110unique_ptrIiNS_14default_deleteIiEEEE` into `std::__1::unique_ptr >` but it doesn't help me to know whether it is reference or not – Bryan Chen Apr 24 '14 at 10:54
  • You know, language-linkage might prevent assigning `std::free` to a pointer of type `void(*)(void*)`: Better use a lambda. Or define your own policy `struct default_free`. – Deduplicator Sep 03 '18 at 10:46
  • @Deduplicator `std::free` doesn’t have language linkage in C++. See §20.2 and §23.10.12. But if language linkage were an issue you could declare your function pointer type accordingly. – Konrad Rudolph Sep 03 '18 at 10:57
  • I'm not sure what in [utility] you want to Point out. [containers] is 23.10, but there's no 23.10.12... – Deduplicator Sep 03 '18 at 11:25
  • To add to that, a Paragraph from [using.linkage]: "*Whether a name from the C standard library declared with external linkage has `extern "C"` or `extern "C++"` linkage is implementation-defined. It is recommended that an implementation use `extern "C++"` linkage for this purpose.179*" And the referenced note: "*179) The only reliable way to declare an object or function signature from the Standard C library is by including the header that declares it, notwithstanding the latitude granted in 7.1.4 of the C Standard.*" – Deduplicator Sep 03 '18 at 11:38
  • @Deduplicator In my version (N4713, compiled 2018-01-16) the section numbers refer to [library.c] and [c.malloc]. The section you quote presumably refers to `::free` etc, *not* `std::free` (which, as part of the C++ standard library, is referred to in the preceding paragraph). That said, this part of the standard could benefit from a clarification. – Konrad Rudolph Sep 03 '18 at 12:03
  • But it is unspecified whether the name is first declared in global scope and then imported into `std`, so it *does* refer to `std::clibraryfunction()` too. – Deduplicator Sep 03 '18 at 12:56
  • @Deduplicator I read this differently: Yes, you’re right, this is unspecified. But my reading is that *if* the implementation imports the global functions into `std`, then it needs to nevertheless somehow ensure their C++ linkage. Otherwise, the declarations shown in [c.malloc] (etc) would be incomplete, and [library.c] seems to indicate that this would be explicitly marked in the standard document. – Konrad Rudolph Sep 03 '18 at 13:08
4

this is what I have ended up with. combined with @Konrad Rudolph's answer and @Joachim Pileborg's comment

std::string demangled(std::string const& sym) {
    std::unique_ptr<char, void(*)(void*)>
    name{abi::__cxa_demangle(sym.c_str(), nullptr, nullptr, nullptr), std::free};
    return {name.get()};
}

template <class T>
void print_type() {
    bool is_lvalue_reference = std::is_lvalue_reference<T>::value;
    bool is_rvalue_reference = std::is_rvalue_reference<T>::value;
    bool is_const = std::is_const<typename std::remove_reference<T>::type>::value;

    std::cout << demangled(typeid(T).name());
    if (is_const) {
        std::cout << " const";
    }
    if (is_lvalue_reference) {
        std::cout << " &";
    }
    if (is_rvalue_reference) {
        std::cout << " &&";
    }
    std::cout << std::endl;
};

int main(int argc, char *argv[])
{   
    auto f = [](auto && a, auto b) {
        std::cout << std::endl;
        print_type<decltype(a)>();
        print_type<decltype(b)>();
    };

    const int i = 1;
    f(i, i);
    f(1, 1);
    f(std::make_unique<int>(2), std::make_unique<int>(2));
    auto const ptr = std::make_unique<int>();
    f(ptr, nullptr);

}

and output

int const &
int

int &&
int

std::__1::unique_ptr<int, std::__1::default_delete<int> > &&
std::__1::unique_ptr<int, std::__1::default_delete<int> >

std::__1::unique_ptr<int, std::__1::default_delete<int> > const &
std::nullptr_t
Community
  • 1
  • 1
Bryan Chen
  • 45,816
  • 18
  • 112
  • 143
  • Hmm. Why is `type_helper` a class rather than a function template? – Konrad Rudolph Apr 24 '14 at 12:02
  • @KonradRudolph yes it should be function template... I was trying to do it differently but end up with this. updated now – Bryan Chen Apr 24 '14 at 12:57
  • I'm sure I'm just missing the right header, but having trouble find which one searching for this error: `print_type_inferred_by_auto.cpp:24:10: error: ‘abi’ has not been declared name{abi::__cxa_demangle(sym.c_str(), nullptr, nullptr, nullptr), std::free};`. I also get this error: `print_type_inferred_by_auto.cpp:24:80: error: no matching function for call to ‘std::unique_ptr::unique_ptr()’ name{abi::__cxa_demangle(sym.c_str(), nullptr, nullptr, nullptr), std::free};` I have C++11 compiler. Is this C++14? – Luv2code Apr 05 '16 at 19:11
0

I mainly want is to know that is the parameter a lvalue ref/rvalue ref/passed by value etc.

Well this is easy.

template<class T>
struct is_lvalue:std::false_type {};
template<class T>
struct is_lvalue<T&>:std::true_type {};
template<class T>
struct is_literal:std::true_type {};
template<class T>
struct is_literal<T&&>:std::false_type {};
template<class T>
struct is_literal<T&>:std::false_type {};// I do not think needed

just do a is_lvalue<decltype(x)>::value and is_value<decltype(x)>::value.

An rvalue (temporary or moved reference) is a non-literal non-lvalue.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524