The following code fails to compile with clang (core dump / ICE) - but it compiles fine with gcc and msvc.
Is my code valid? Can I change something that would work with current clang version.
#include <type_traits>
#include <iostream>
struct A {
void Func() {
}
};
struct B {
static void Func() {
std::cout << "Hello from struct \n";
}
};
template<typename T>
void Do(){
auto lambda = [](auto&& cls) -> decltype(
std::remove_const_t<std::remove_reference_t<decltype(cls)>>::Func()
) {};
if constexpr (!std::is_invocable_v<decltype(lambda), A>){
std::cout << "no static Foo\n";
} else{
T::Foo();
}
}
int main()
{
Do<A>();
Do<B>();
return 0;
}
The idea of this code is to detect if for example S::Func() is a valid expression.
Related
Consider following code snippet:
class Foo {
public:
void bar(std::size_t){}
void bar(const char* ){}
};
int main() {
auto foo = Foo{};
foo.bar(0);
}
It produces ambiguous calls errors (check here). But I think from programmer's perspective it is pretty obvious that I want to call overload with std::size_t. My question is if anything can be done so this code does not produce errors and calls size_t overload?
can be done like this in C++ 20
#include <cstdint>
#include <iostream>
#include <type_traits>
class Foo {
public:
template <typename T>
requires std::is_integral_v<T>
void bar(T){
std::cout<<"hello size_T";
}
void bar(const char* ){
std::cout<<"hello";
}
};
int main() {
auto foo = Foo{};
foo.bar(25);
}
In modern c++ (at least c++17), we prefer to pass string_view as argument over const char* for the none owner transfer cases, so a considerable choice:
#include <cctype>
#include <string>
class Foo {
public:
void bar(std::size_t){}
void bar(std::string_view){}
};
int main() {
auto foo = Foo{};
foo.bar(0);
}
Online demo
In below C++ 20, this works well.
#include <iostream>
class Foo {
public:
template <typename T>
void bar(T) {
std::cout << "hello T" << std::endl;
}
void bar(const char* c) {
std::cout << c << std::endl;
}
};
int main() {
auto foo = Foo{};
foo.bar(0);
foo.bar("test.");
}
This works in C++23:
foo.bar(0zu);
and this works pre-C++23:
foo.bar(size_t{0});
I'm not sure about this piece of code:
#include <functional>
#include <list>
#include <iostream>
void f() { std::cout << "HI!\n"; }
struct fobj
{
void operator()() const { std::cout << "Bye!\n"; }
};
using slot_t = std::function<void()>;
std::list<slot_t> slot_list;
template<class F>
inline std::size_t insert_slot(F f)
{
auto it = slot_list.insert(slot_list.begin(), f);
return reinterpret_cast<std::size_t>(&*it);
}
inline slot_t& recover_slot(std::size_t conn_id)
{ return *reinterpret_cast<slot_t*>(conn_id); }
int main()
{
std::size_t conn1_id = insert_slot(f);
std::size_t conn2_id = insert_slot(fobj());
recover_slot(conn1_id)(); // HI!
recover_slot(conn2_id)(); // Bye!
}
I don't see the reinterpret_cast<T*>(some_size_t) any different from static_cast<T*>(some_void_ptr), but I'm not really sure how risky the former is.
This C++ code compiles successfully with VS 2012 but crashes at runtime:
#include <iostream>
#include <functional>
void f()
{
std::cout << "f called" << std::endl;
}
int main()
{
auto get_f= []()
{
bool b = true;
return b ? f : f;
};
std::function<void()> filter(get_f()); // crash here!!!
return 0;
}
If we change get_f to this:
auto get_f= []()
{
return f;
};
then program runs without crashes.
Is it a problem with this code or compiler/std library bug?
I have not tested with newer versions of Visual Studio.
It looks to me like a problem with the standard library (or possibly compiler).
With VS 2013, it compiles and runs without a problem. If we add code to invoke the filter that runs as well:
#include <iostream>
#include <functional>
void f()
{
std::cout << "f called" << std::endl;
}
int main()
{
auto get_f= []()
{
bool b = true;
return b ? f : f;
};
std::function<void()> filter(get_f()); // crash here!!!
filter();
return 0;
}
Output: f called
Ok. Here code:
#include <iostream>
using namespace std;
template<typename T>
struct A {
enum Status {
one = 1
};
template< Status status >
struct C;
};
template<typename T>
template<typename A<T>::Status status >
struct A<T>::C {
void operator()() {
cout << "C: " << (int)status << endl;
};
// void operator()();
};
// template<typename T>
// template<typename A<T>::Status status >
// void A<T>::C<status>::operator()() {
// cout << "C: " << status << endl;
//}
int main()
{
A<int>::C<A<int>::one> c;
c();
return 0;
}
And it works with clang and g++ - compile and run.
But, if comment inline implementation A::C::operator()(), and uncomment commented declaration and out implementation:
#include <iostream>
using namespace std;
template<typename T>
struct A {
enum Status {
one = 1
};
template< Status status >
struct C;
};
template<typename T>
template<typename A<T>::Status status >
struct A<T>::C {
// void operator()() {
// cout << "C: " << (int)status << endl;
// };
void operator()();
};
template<typename T>
template<typename A<T>::Status status >
void A<T>::C<status>::operator()() {
cout << "C: " << status << endl;
}
int main()
{
A<int>::C<A<int>::one> c;
c();
return 0;
}
clang doesn't make this:
$ clang++ -std=c++11 main.cpp && ./a.out
main.cpp:28:23: error: nested name specifier 'A<T>::C<status>::' for declaration does not refer into a class, class template or class template partial specialization
void A<T>::C<status>::operator()() {
~~~~~~~~~~~~~~~~~^
1 error generated.
but g++ really works:
$ g++-4.8 -std=c++11 -O2 -Wall -pedantic -pthread main.cpp
C: 1
I tried compile code with Visual C++ 2010 on work PC but both samples failed. I can't verify it now (no windows PC) and I'm not sure - maybe I made other mistakes...
Where mistake in second sample and what syntax right for out implementation?
It looks to me that you are just forgot the template parameter in the implementation of struct C.
The following fixed code compiles file in Visual C++ 2010:
#include <iostream>
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
template<typename T>
struct A {
enum Status {
one = 1
};
template< Status status >
struct C;
};
template<typename T>
template<typename A<T>::Status status >
struct A<T>::C<status> {
/*void operator()() {
cout << "C: " << (int)status << endl;
};*/
void operator()();
};
template<typename T>
template<typename A<T>::Status status >
void A<T>::C<status>::operator()() {
cout << "C: " << status << endl;
}
int main()
{
A<int>::C<A<int>::one> c;
c();
return 0;
}
The code below does not compile on Ideone or Codepad, yielding errors like:
'X' was not declared in this scope
but it does on VC++ 2010:
#include <iostream>
#include <typeinfo>
template<typename T>
struct Base
{
typedef T X;
};
template<typename T>
struct Derived
:
Base<T>
{
static void print()
{
std::cout << typeid(X).name() << "\n";
}
};
int main()
{
Derived<int>::print();
Derived<char>::print();
Derived<float>::print();
return 0;
}
where it prints int, char and float. Should I change my code to:
template<typename T>
struct Derived
{
typedef Base<T> B;
static void print()
{
std::cout << typeid(typename B::X).name() << "\n";
}
};
in order to be standard-conforming?
If you meant the equivalent of this (note you have dropped the inheritance in your example):
template<typename T>
struct Derived : Base<T> {
static void print() {
std::cout << typeid(typename Base<T>::X).name() << "\n";
}
};
then yes, that is standard compliant code. But note that the result of typeid(some type).name() is implementation dependent. On GCC your main produces i, c and f.
$ g++ -Wall test.cpp
test.cpp: In static member function 'static void Derived::print()':
test.cpp:15:37: error: 'X' was not declared in this scope
$ g++ --version
g++ (SUSE Linux) 4.6.2