Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
VS2017の新機能

辞世の句

PMPやってたらコンパイラ間の挙動の違いに飲み込まれて死んだ。大体msvcが悪い。(自由律)

はじめに

この記事はC++アドベントカレンダー4日目の記事です。
昨日はコンパイル中にコンパイルする「コンパイル時Cコンパイラ」をつくった話でした。

先日VS2017RCが出ました。VC++のコア言語とライブラリに関して新機能をチェックしていこうという記事です。全部は無理ですが。

以下プロパティの言語標準を「ISO C++ 標準の最終草案 (/std:c++latest)」にしていることを前提とします。

コア言語編

variable templates

constexpr定数に限りtemplateな定数を宣言することが可能になりました。

#include<iostream>
template<class T>constexpr auto test = sizeof(T) + 3;

int main()
{
    std::cout<<test<int><<std::endl;
}

extended constexpr

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;
}

[[deprecated]] attributes

C++標準の形で非推奨であるという属性を追加できます。

#include<iostream>

[[deprecated]] int hoge()
{
	return 1;
}
int main()
{
	std::cout << hoge() << std::endl;//警告が出る
}

terse static assert

static_assertの第2引数を省略できます。

int main()
{
	static_assert(true);
	static_assert(false);
}

nested namespace definitions

ネストした名前空間での定義を簡略化できます。

#include<iostream>

namespace test::hage
{
	int hoge()
	{
		return 1;
	}
}

int main()
{
	std::cout << test::hage::hoge() << std::endl;
}

std::uncaught_exceptions

現在キャッチされていない例外の数を数える関数です。 シングルスレッドだと高々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();
}

標準ライブラリ

any

動的型となる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;
}

variant

型安全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);
}

optional

無効値を取りうることを示す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;
}

string_view

所有権を持たない文字列型である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;
}

std::make_integer_sequence

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++かなぁって思います。

参考

VS2017のリリースノート C++17の新機能予定 - Faith and Brave - C++で遊ぼう

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment