I am trying to use std::optional but my code raise error.
I have specified #include <experimental/optional> and compiler options are -std=c++1z, -lc++experimental.
How to use std::experimental::optional?
The following is code:
#include <experimental/optional>
#include <iostream>
std::experimental::optional<int> my_div(int x, int y) {
if (y != 0) {
int b = x / y;
return {b};
}
else {
return {};
}
}
int main() {
auto res = my_div(6, 2);
if (res) {
int p = res.value();
std::cout << p << std::endl;
}
}
error message:
optional.cpp:17:21: error: call to unavailable member function 'value':
int p = res.value();
~~~~^~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/experimental/optional:525:17: note: candidate function has been explicitly made unavailable
value_type& value()
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/experimental/optional:517:33: note: candidate function has been explicitly made unavailable
constexpr value_type const& value() const
^
1 error generated.
OS: macOS 10.12.5
Compiler version:
Apple LLVM version 8.1.0 (clang-802.0.42)
Target: x86_64-apple-darwin16.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
Okay, after you posted your error, I could look into that (but you could have done exactly the same).
IN SHORT
This is a problem/bug with optional as provided by Apple on OSX, but there is an easy workaround.
WHAT'S GOING ON
The file /Library/Developer/CommandLineTools/usr/include/c++/v1/experimental/optional declares the offending function optional::value as
template <class _Tp>
class optional
: private __optional_storage<_Tp>
{
/* ... */
_LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS
constexpr value_type const& value() const
{
if (!this->__engaged_)
throw bad_optional_access();
return this->__val_;
}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS
value_type& value()
{
if (!this->__engaged_)
throw bad_optional_access();
return this->__val_;
}
/* ... */
};
Running the preprocessor only (compiler option -E) reveals that the macros expand to
#define _LIBCPP_INLINE_VISIBILITY \
__attribute__ ((__visibility__("hidden"), __always_inline__))
#define _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS \
__attribute__((unavailable))
In particular, the macro _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS is #defined in file /Library/Developer/CommandLineTools/usr/include/c++/v1/__config as
// Define availability macros.
#if defined(_LIBCPP_USE_AVAILABILITY_APPLE)
// ...
#define _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS __attribute__((unavailable))
// ...
#else
// ...
#define _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS
// ...
#endif
Thus, this is a Apple specific change from LLVM's libc++ API. As the name of the macro implies, the reason is that Apple does not make
class bad_optional_access
: public std::logic_error
{
public:
bad_optional_access() : std::logic_error("Bad optional Access") {}
virtual ~bad_optional_access() noexcept;
};
available and hence cannot implement functionality (optional::value) that depends on it. Why bad_optional_access is not provided (thereby breaking the standard) is unclear, but it may have to do with the fact that a library (dylib) must be altered to contain bad_optional_access::~bad_optional_access().
HOW TO WORK AROUND
simply use optional::operator* instead
int p = *res;
The only real difference is that no access check is done. If you need that, do it yourself
template<typename T>
T& get_value(std::experimental::optional<T> &opt)
{
if(!opt.has_value())
throw std::logic_error("bad optional access");
return *opt;
}
template<typename T>
T const& get_value(std::experimental::optional<T>const &opt)
{
if(!opt.has_value())
throw std::logic_error("bad optional access");
return *opt;
}
Related
For simplicity, I will omit things like proper typedefs to opaque structs instead of void *, Windows calling conventions, fixed integer types, etc.
Suppose I have the following files:
CApi.h -- Shared library header with C linkage for portability and hiding proprietary code.
#define LIB_API // library import/export details
extern "C" {
typedef int error;
error LIB_API lib_foo_create(void ** foo);
error LIB_API lib_foo_destroy(void * foo);
error LIB_API lib_foo_func(void * foo, int * out);
error LIB_API lib_bar_create(void ** bar);
error LIB_API lib_bar_destroy(void * bar);
error LIB_API lib_bar_func(void * bar, int * out); // Suppose this internally uses Foo::func from CxxApi.hpp with C++17
} // extern C
CxxApi.hpp -- Header only wrapper to simplify API usage.
#include "CApi.h"
namespace lib {
namespace detail {
template < typename Return = void, typename Func, typename... Args >
Return c_api(Func func)
{
// Not sure how this affects ODR if client and provider code use different versions,
// but neither see each other's code usage.
#if __cplusplus >= 201703L // C++17
// more efficient implmentation (e.g. fold expressions)
#else
// fallback implmentation (e.g. recursion)
#endif
}
} // namespace lib::detail
class Foo
{
public:
Foo() { detail::c_api(lib_foo_create, &handle_); }
~Foo() { detail::c_api(lib_foo_destroy, handle_); }
int func() { return detail::c_api<int>(lib_foo_func, handle_); }
private:
void * handle_;
};
struct Bar
{
public:
Bar() { detail::c_api(lib_bar_create, &handle_); }
~Bar() { detail::c_api(lib_bar_destroy, handle_); }
int func() { return detail::c_api<int>(lib_bar_func, handle_); }
private:
void * handle_;
};
} // namespace lib
If I, the API provider, compile this using C++17, but the client using the API uses C++11, is ODR violated with lib::detail::c_api?
I believe it is not because lib_bar_func's definition is in a different translation unit than client code, but I am not positive.
I am building my program by using the latest Emscripten compiler.
It is based on Clang version 14. Actually it is a small test program which is the following:
#include <iostream>
struct Test {
template<typename T>
static inline void Dump(const T& value) {
std::cout << "[generic] = '" << value << "'\n";
}
template<>
static inline void Dump<std::string>(const std::string& value) {
std::cout << "[std::string] = '" << value << "'\n";
}
};
int main() {
std::string text = "hello";
Test::Dump(text);
return 0;
}
When I build it by Emscripten compiler I got the warning:
D:\em_test>emcc a.cpp
a.cpp:10:24: warning: explicit specialization cannot have a storage class
static inline void Dump<std::string>(const std::string& value) {
~~~~~~~ ^
1 warning generated.
If I just remove static keyword from void Dump<std::string> line
then there will be no warning. However, this code will cause compilation error in Visual Studio:
D:\em_test\a.cpp(17,11): error C2352: 'Test::Dump': illegal call of non-static member function
But this error is expected and clear.
I would like to write a cross-platform program.
So, I think I should simple disable this warning in Emscripten.
However, I can not find any Emscripten (which is based on clang version 14)
command line option for that!
And I am asking advice for that.
Actually I tried to use -Wno-static-inline-explicit-instantiation command line option but it did not help:
D:\em_test>emcc -Wno-static-inline-explicit-instantiation a.cpp
a.cpp:10:24: warning: explicit specialization cannot have a storage class
static inline void Dump<std::string>(const std::string& value) {
~~~~~~~ ^
1 warning generated.
However, I see in Clang version 13 user manual description about -Wstatic-inline-explicit-instantiation option but it is about a slightly another warning text.
Also it seems that Clang version 14 is not fully released, so, there is no public Clang version 14 user manual.
I can not find any Emscripten or Clang command line option to disable the above warning.
Could somebody help me?
Explicit specialization of (both static and non-static) function templates cannot be put into class definitions.
Just put it into the enclosing namespace(i.e somewhere after the class):
#include <iostream>
struct Test {
template <typename T>
static inline void Dump(const T& value) {
std::cout << "[generic] = '" << value << "'\n";
}
};
// Notice Test::
template <>
inline void Test::Dump<std::string>(const std::string& value) {
std::cout << "[std::string] = '" << value << "'\n";
}
int main() {
std::string text = "hello";
Test::Dump(text);
return 0;
}
inline is never necessary for in-class function definitions but it has different meaning for member variables.
inline for out-class is necessary in header files because the explicit specialization is not a template anymore.
Suppose I want to use coroutines with C++20 and restrict the promise type to accept only functions getting one argument of type int &. I write the following code:
#include <coroutine>
struct task {
struct promise_type {
promise_type(int &) {}
task get_return_object() { return {}; }
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {}
};
};
task my_task(int &) {
co_await std::suspend_never{};
}
int main() {
int x = 5;
my_task(x);
}
This compiles and works fine, both with GCC version 10+ and Visual Studio 2019 version 16.8+.
However, Visual Studio 2019 always complains that no default constructor exists for class "task::promise_type":
This error does not occur if I do not use a reference (e.g. int instead of int & as the argument type).
GCC does not show any warning or error, with and without the reference.
Am I doing something wrong?
Is this prohibited by the standard?
Or is it just a weird quirk of IntelliSense?
This seems to be a problem of IntelliSense and should work fine. To resolve the intellisense error, a constructor can be added just for IntelliSense:
#ifdef __INTELLISENSE__
promise_type();
#endif
If I have a class with std::atomic_bool or std::mutex member for example, and if I put this class inside std::variant, my g++ will complain with "no matching function for call to std::variant<....>". Now I have to declare my std::mutex member to be static.
g++ (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5) Copyright (C) 2017 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Actual code
#include <iostream>
#include <variant>
#include <mutex>
enum class enFixEngineRunMode {
eFixModeStreet // Fix connection side as initiator/client
,eFixModeStreetStandAlone // Fix connection side as initiator/client
,eFixModeStreetAccpt // Fix connection side as acceptor/server
,eFixModeStreetAccptStandAlone // Fix connection side as acceptor/server
,eFixModeClient // Fix connection side as acceptor/client
,eFixModeClientStandAlone // Fix connection side as acceptor/client
,eFixModeClientInit // Fix connection side as initiator/server
,eFixModeClientInitStandAlone // Fix connection side as initiator/server
,eFixModeInvalid
};
struct FOO {
FOO(int any) { }
void operator()() const {
std::cout << "FOO2" << std::endl;
}
};
template <enum enFixEngineRunMode>
struct BAR {
BAR(double any) { }
void operator()() const {
std::cout << "BAR2" << std::endl;
}
std::mutex m_metux;
};
template<>
struct BAR<enFixEngineRunMode::eFixModeStreetStandAlone> {
BAR(double any) { }
void operator()() const {
std::cout << "eFixModeStreetStandAlone" << std::endl;
}
};
using EngineImpl = std::variant<BAR<enFixEngineRunMode::eFixModeStreet>
, BAR<enFixEngineRunMode::eFixModeStreetStandAlone>
, BAR<enFixEngineRunMode::eFixModeStreetAccpt>
, BAR<enFixEngineRunMode::eFixModeStreetAccptStandAlone>
, BAR<enFixEngineRunMode::eFixModeClient>
, BAR<enFixEngineRunMode::eFixModeClientStandAlone>
, BAR<enFixEngineRunMode::eFixModeClientInit>
, BAR<enFixEngineRunMode::eFixModeClientInitStandAlone>
, BAR<enFixEngineRunMode::eFixModeInvalid>>;
struct Engine {
Engine() : m_engine([&] {
int i = 2;
if (1 == i)
return EngineImpl(BAR<enFixEngineRunMode::eFixModeStreetStandAlone>(0.0));
else return EngineImpl(BAR<enFixEngineRunMode::eFixModeStreet>(0.0));
}()) {}
void operator()() const {
std::visit([](auto const& e){ e(); }, m_engine);
}
EngineImpl m_engine;
};
int main(int argc, const char *argv[], char** env)
{
Engine e;
e();
return 0;
}
compilation error:
variantMain2.cpp:57:70: error: no matching function for call to ‘std::variant<BAR<(enFixEngineRunMode)0>, BAR<(enFixEngineRunMode)1>, BAR<(enFixEngineRunMode)2>, BAR<(enFixEngineRunMode)3>, BAR<(enFixEngineRunMode)4>, BAR<(enFixEngineRunMode)5>, BAR<(enFixEngineRunMode)6>, BAR<(enFixEngineRunMode)7>, BAR<(enFixEngineRunMode)8> >::variant(BAR<(enFixEngineRunMode)0>)’
else return EngineImpl(BAR<enFixEngineRunMode::eFixModeStreet>(0.0));
^
In file included from variantMain2.cpp:2:0:
/opt/rh/devtoolset-7/root/usr/include/c++/7/variant:986:2: note: candidate: template<long unsigned int _Np, class _Up, class ... _Args, class> constexpr std::variant<_Types>::variant(std::in_place_index_t<_Np>, std::initializer_list<_Up>, _Args&& ...)
variant(in_place_index_t<_Np>, initializer_list<_Up> __il,
^~~~~~~
/opt/rh/devtoolset-7/root/usr/include/c++/7/variant:986:2: note: template argument deduction/substitution failed:
variantMain2.cpp:57:70: note: ‘BAR<(enFixEngineRunMode)0>’ is not derived from ‘std::in_place_index_t<_Idx>’
else return EngineImpl(BAR<enFixEngineRunMode::eFixModeStreet>(0.0));
^
In file included from variantMain2.cpp:2:0:
/opt/rh/devtoolset-7/root/usr/include/c++/7/variant:977:2: note: candidate: template<long unsigned int _Np, class ... _Args, class> constexpr std::variant<_Types>::variant(std::in_place_index_t<_Np>, _Args&& ...)
variant(in_place_index_t<_Np>, _Args&&... __args)
Because std::variant is not an aggregate, it must move its arguments into its internal storage, and std::mutex is not movable (because doing so would break any concurrent users). Your choices are to make BAR movable (e.g., by storing a std::unique_ptr<std::mutex>), or to avoid the move by using std::in_place_type to construct the object inside the variant.
Let's say I have a template function that takes an integer and a const reference to an instance of type T. Now depending on the integer, only some T's are acceptible, otherwise an exception is thrown at runtime.
If all uses of this function would use constant integers, it would be possible to make the int a template parameter and use a static assertion to check if it is acceptable. So instead of func(1,c) one would use func<1>(c) and would gain compile-time type checking. Is there any way to write func(1,c) and still keep the compile-time check, while also being able to write func(i,c) and use a dynamic assertion? The goal is to make it transparent to the developer. It would simply be great to add this safety without bothering the developers about things like compile-time constants. They'd probably only remember that func(1,c) always works and use that, avoiding the check.
How can I define a function with a static assertion whenever possible and a dynamic assertion otherwise?
The following code shows the solution for GCC by Ivan Shcherbakov:
#include <iostream>
#include <cassert>
template<typename T>
void __attribute__((always_inline)) func(const int& i, const T& t);
void compile_time_error_() __attribute__((__error__ ("assertion failed")));
template<>
void __attribute__((always_inline))
func(const int& i, const float& t)
{
do {
if (i != 0) {
if (__builtin_constant_p(i)) compile_time_error_();
std::cerr << "assertion xzy failed" << std::endl;
exit(1);
}
} while (0);
func_impl<float>(i,t);
}
This will only allow the combination of i=0 and T=float. For other combinations a good way would be creating a Macro that produces the code of template<> func(const int& i, const T& t) with T and i != 0 replaced.
Well, if you're using GCC, you can use a dirty hack, but it will only work when function inlining is enabled (-O1 or more):
void my_error() __attribute__((__error__ ("Your message here")));
template <typename T1, typename T2> struct compare_types
{
enum {Equals = 0};
};
template <typename T1> struct compare_types<T1,T1>
{
enum {Equals = 1};
};
template <typename Type> __attribute__((always_inline)) void func(int a, Type &x)
{
if (__builtin_constant_p(a))
{
if (a == 1 && compare_types<Type,char>::Equals)
my_error();
}
}
In this case when a == 1 and Type is char, you'll get an error. Here's an example that will trigger it:
int main()
{
char x;
func(1, x);
return 0;
}
Note that this example heavily relies on the gcc-specific __builtin_constant_p() function and won't work with other compilers!
Let me paraphrase question to be more accurate in my answer:
Can runtime assert sometimes report errors on compile time.
Gcc can, but only on some optimization level and error message is
very uninformative. Clang itself can't (no error attribute), but do
not forget about clang analyzer.
Analyzer can report some runtime errors like dereferencing null pointer.
So here is an idea and simple test of 'smart' runtime assert:
#include <cstdlib> // std::abort
#if !defined(__clang__) && defined(__GNUC__)
// clang emulates gcc
# define GCC_COMPILER 1
#else
# define GCC_COMPILER 0
#endif
#if GCC_COMPILER
void assertion_failed_message() __attribute__((__error__("assertion failed")));
#endif
inline void smart_assert(bool condition) {
#if GCC_COMPILER
// gcc is very 'sensitive', it must be first code lines in this function
if (__builtin_constant_p(condition) && !condition) {
assertion_failed_message();
}
#endif
if (condition) {
// Ok
return;
}
#if defined(__clang_analyzer__)
enum {
ASSERTION_FAILED = 0xdeadfull
};
int *a = nullptr;
*a = ASSERTION_FAILED;
#endif
// Implement some standart error, like abort
std::abort();
}
void test_condition_2(bool condition) {
smart_assert(condition);
}
void test_condition_1(bool condition) {
test_condition_2(condition);
}
void test_condition_0(bool condition) {
test_condition_1(condition);
}
int main() {
test_condition_0(0==1);
return EXIT_SUCCESS;
}
Gcc report error at O2 optimization level, it's good. But report message
is in main function, and don't leave any information
about test_condition_{0,1,2}.
Clang analyzer report error and if you use Xcode, you can see all path
from main to smart_assert:
P.S. clang analyzer is not perfect, so if you try test_condition_0(argc),
no error will be reported (truely runtime check), but if you try
test_condition_0(argc==1), false positive will be reported.