規格によるとstd::tuple
、以下のメンバー機能があります
constexpr tuple();
explicit tuple(const Types&...);
誰かが何のために起こることになっているのか説明してもらえますかstd::tuple<>
?
規格によるとstd::tuple
、以下のメンバー機能があります
constexpr tuple();
explicit tuple(const Types&...);
誰かが何のために起こることになっているのか説明してもらえますかstd::tuple<>
?
標準で与えられている定義は擬似コードであると思われます。これは、標準の定義の多くに当てはまります。口頭で与えられるいくつかの要件が含まれていますが、のようなトリックでのみ満足できenable_if
ます。これは、C ++のような擬似コード表記が、そのような空のタプルをインスタンス化しようとしたときに、実際には不正なC ++につながる可能性がある例のようです(または単に省略されている可能性があります)。
stdlibc++とlibc++はどちらも、ゼロ要素タプルを明示的に特殊化しています。たとえば、stdlibc++では次のようになります。
// Explicit specialization, zero-element tuple.
template<>
class tuple<>
{
public:
void swap(tuple&) noexcept { /* no-op */ }
};
暗黙的に定義された明確なデフォルトコンストラクターを使用します。
Libc ++は、パラメーターなしのデフォルトコンストラクターを明示的に宣言しません。おそらく、テンプレート化されたコンストラクターが、空でないタプルのデフォルトコンストラクターとして選択されます。
興味深いことに、2つのライブラリは、空のタプルがどのメンバーを持っているかについて意見が分かれています。たとえば、以下はlibc ++でコンパイルされますが、libstdc++ではコンパイルされません。
#include <tuple>
#include <memory>
int main() {
std::tuple<> t(std::allocator_arg, std::allocator<int>());
}
I believe this is a minor error in the standard. Clearly, when the Types
parameter pack is empty, the two constructor calls are equivalent and cannot be overloaded (see C++11 section 13). (Further note that the constructor using Types
is not a member template either --if it was, then it would be a legal overload.).
In other words, this code will not compile:
template <typename... Types>
struct Test
{
constexpr Test() {}
explicit Test(Types const&...) { /* etc. */ }
};
int main()
{
Test<> a;
Test<int> b;
}
e.g., a g++ v4.8 snapshot outputs:
tt.cxx: In instantiation of ‘struct Test<>’:
tt.cxx:10:10: required from here
tt.cxx:5:12: error: ‘Test<Types>::Test(const Types& ...) [with Types = {}]’ cannot be overloaded
explicit Test(Types const&...) { /* etc. */ }
^
tt.cxx:4:13: error: with ‘constexpr Test<Types>::Test() [with Types = {}]’
constexpr Test() {}
^
This can be fixed by using partial specialization:
template <typename... Types>
struct Test
{
constexpr Test() {} // default construct all elements
explicit Test(Types const&...) { /* etc. */ }
// and all other member definitions
};
template <>
struct Test<>
{
constexpr Test() {}
// and any other member definitions that make sense with no types
};
int main()
{
Test<> a;
Test<int> b;
}
which will compile correctly.
It appears the standard wanted a constexpr
default constructor was so that std::tuple<> var;
could be written instead of writing std::tuple<> var();
or std::tuple<> var{};
because of the use of explicit
with the other constructor. Unfortunately, its definition of std::tuple
does not work for tuples of size zero. The standard does permit such in section 20.4.2.7 (relational operators) though, "For any two zero-length tuples, [...]". Oops! :-)
一見すると、あいまいさはそれが呼び出された時点でのみ問題になり、通常の過負荷解決が得られます。