在Java中,我们可以声明一个blank final
变量并在以后对其进行初始化。编译器将确保初始化仅发生一次 -初始化失败或双重初始化都是编译时错误。例如:
public int bar() {
return 66;
}
public void foo() {
final int x; // declare the variable
...
x = bar(); // initialization only once
}
在Java中,编译器可以保证绝对不会在第一次分配之前在任何代码路径上分配x
,并且可以保证绝对不会在任何代码路径上第二次分配const
。 (有关更多信息,请参见Chapter 16, Definite Assignment, of the Java Language Specification。)
我们如何在C ++中实现类似的行为?是否可以将变量声明为const
但推迟其初始化? (无需丢弃final _auth = FirebaseAuth.instance;
_auth.onAuthStateChanged.listen((user) {
if (user != null) {
//get useer data
} else {
//go to login page
}
});
Future<Null> _loginByFacebook(Completer completer) async {
FacebookLogin facebookLogin = new FacebookLogin();
FacebookLoginResult result = await facebookLogin.logInWithReadPermissions(['email', 'public_profile']);
switch (result.status) {
case FacebookLoginStatus.loggedIn:
AuthCredential credential = FacebookAuthProvider.getCredential(accessToken: result.accessToken.token);
FirebaseAuth.instance.signInWithCredential(credential);
completer.complete();
break;
case FacebookLoginStatus.cancelledByUser:
break;
case FacebookLoginStatus.error:
completer.completeError(result.errorMessage);
}
}
Future<Null> _loginByGoogle( Completer completer) async {
try {
await GoogleSignIn().signIn();
completer.complete();
} catch (error) {
completer.completeError(error);
print(error);
}
}
说明符。)
答案 0 :(得分:3)
除非定义了常量,否则无法初始化const。您必须找到一种方法来知道其定义位置的价值。如果x
的值难以确定,请考虑使用
const int x = calc_x();
或类似
的闭包const int x = []() { /* code to calculate x's value */ }();
const
的性质是对象类型的一部分,并且在任何情况下都不能更改对象类型,因此x
是const
,您以后不能对其进行初始化或x
根本不是const
。
可以设计一个可以对此进行模拟的包装器class
,但充其量您会遇到运行时错误。
请注意,似乎有一种const_cast
形式的解决方案,但是它假定所讨论的对象实际上不是const
。对于const int x
,初始化后无法合法更改其值。
答案 1 :(得分:3)
C ++对此没有内置功能。不过,您可以自己构建它。您可以创建一个类来保存所需类型的对象的存储,并且可以为此操作重载赋值运算符,因此它只能被调用和初始化一次。看起来像
template<typename T>
class once
{
private:
std::aligned_storage_t<sizeof(T), alignof(T)> data;
T* ptr = nullptr;
public:
once() = default;
~once()
{
if(ptr) // it is initialized so call the destructor
ptr->~T();
// optionally you can add
// throw("a once<T> must be initialized once");
// this can help to enforce that the object is actually initialized as you'll get a runtime exception in code that does not do so
}
template<typename U>
once& operator =(U&& value)
{
if (!ptr) // it is not initialized so call constructor
{
ptr = new(&data) T(std::forward<U>(value));
}
else
throw ("can only assign to a once<T> once.");
return *this;
}
operator const T&()
{
return *ptr;
}
};
然后您将使用它
int main()
{
once<int> foo;
if (1 < -1)
foo = 21;
else
foo = 42;
std::cout << foo;
//foo = 23; // uncomment this to get an exception.
}