PMPやってたらコンパイラ間の挙動の違いに飲み込まれて死んだ。大体msvcが悪い。(自由律)
この記事はC++アドベントカレンダー4日目の記事です。
昨日はコンパイル中にコンパイルする「コンパイル時Cコンパイラ」をつくった話でした。
先日VS2017RCが出ました。VC++のコア言語とライブラリに関して新機能をチェックしていこうという記事です。全部は無理ですが。
以下プロパティの言語標準を「ISO C++ 標準の最終草案 (/std:c++latest)」にしていることを前提とします。
constexpr定数に限りtemplateな定数を宣言することが可能になりました。
#include<iostream>
template<class T>constexpr auto test = sizeof(T) + 3;
int main()
{
std::cout<<test<int><<std::endl;
}
constexpr関数の制限が緩和されました。
#include<iostream>
constexpr int sum(int x)
{
int ret{};
for(int i=1; i<=x; ++i)
{
ret+=i;
}
return ret;
}
int main()
{
std::cout<<sum(10)<<std::endl;
}
C++標準の形で非推奨であるという属性を追加できます。
#include<iostream>
[[deprecated]] int hoge()
{
return 1;
}
int main()
{
std::cout << hoge() << std::endl;//警告が出る
}
static_assertの第2引数を省略できます。
int main()
{
static_assert(true);
static_assert(false);
}
ネストした名前空間での定義を簡略化できます。
#include<iostream>
namespace test::hage
{
int hoge()
{
return 1;
}
}
int main()
{
std::cout << test::hage::hoge() << std::endl;
}
現在キャッチされていない例外の数を数える関数です。 シングルスレッドだと高々1つ (投げられた例外を放置した状態で別な例外が投げられたらstd::terminateが呼ばれるため) ですがマルチスレッドだと2以上になりえます。
#include<iostream>
#include<thread>
#include<exception>
#include<mutex>
std::mutex mutex;
void print(int x, int y)
{
mutex.lock();
std::cout << "(" << x << "," << y << ")" << std::endl;
mutex.unlock();
}
struct test
{
int x;
test(int v) :x(v)
{
}
~test()
{
print(x, std::uncaught_exceptions());
std::this_thread::sleep_for(std::chrono::seconds(1));
}
};
int main()
{
std::thread thread([]()
{
try
{
test t(1);
throw 1;
}
catch (int)
{
}
});
try
{
test t(2);
throw 2;
}
catch (int)
{
}
thread.join();
}
動的型となるstd::anyが追加されました。
#include<any>
#include<iostream>
int main()
{
std::any val = 1;
std::cout << std::any_cast<int>(val) << std::endl;
val = "test";
std::cout << std::any_cast<char const*>(val) << std::endl;
}
型安全unionであるstd::variantが追加されました。
#include<variant>
#include<iostream>
#include<string>
void print(int v)
{
std::cout << "int:" << v << std::endl;
}
void print(std::string const& str)
{
std::cout << "string:" << str << std::endl;
}
void print(std::variant<int, std::string>const& val)
{
if (val.index() == 0)
{
print(std::get<int>(val));
}
else
{
print(std::get<std::string>(val));
}
}
int main()
{
std::variant<int, std::string> val;
val = 1;
print(val);
val = std::string("test");
print(val);
}
無効値を取りうることを示すstd::optionalが追加されました。
#include<optional>
#include<iostream>
int main()
{
std::optional<int> opt = 1;
std::cout << opt.has_value() << ":" << *opt <<std::endl;
opt = std::nullopt;
std::cout << opt.has_value() << std::endl;
}
所有権を持たない文字列型であるstd::string_viewが追加されました。
#include<iostream>
#include<string_view>
#include<string>
int main()
{
std::string str = "123456789";
std::string_view view = str;
std::cout << view << std::endl;
auto view2 = view.substr(3, 3);
std::cout << view2 << std::endl;
str = "987654321";
std::cout << view << std::endl;
std::cout << view2 << std::endl;
}
VS2015では再帰深度がO(N)だったstd::make_integer_sequenceの再帰深度が変更になりました。具体的にはコンパイラマジックでO(1)になります。
#include<utility>
template<std::size_t I, std::size_t U>struct test
{
typedef typename test<I-1, U>::type type;
};
template<std::size_t U>struct test<0, U>
{
typedef std::make_index_sequence<U> type;
};
int main()
{
//typedef test<500, 1>::type typeA;
typedef test<495, 20000>::type typeB;
}
VC++はまた一歩C++に近づいたような気がしますがその割にtwo-phase lookupをいつまでたっても実装しないので やっぱりVC++はVC++かなぁって思います。