compiler error: is private within this context only on gcc9 with c++17
compiler error: is private within this context only on gcc9 with c++17
我使用 travis 测试我的代码。最近有人将 gcc9 添加到用于测试代码的编译器集中。虽然使用 gcc8(使用 c++14 和 c++17)和使用 c++14 的 gcc-9.1.0 编译一切正常,但使用 c++17 的 gcc-9.1.0 失败并出现以下错误:
/usr/include/c++/9/functional: In instantiation of ‘std::_Bind<_Functor(_Bound_args ...)>::_Bind(const _Functor&, _Args&& ...) [with _Args = {std::tuple<int>}; _Functor = SQLite::Statement; _Bound_args = {std::tuple<int>}]’:
/usr/include/c++/9/functional:811:38: required from ‘typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type std::bind(_Func&&, _BoundArgs&& ...) [with _Func = SQLite::Statement&; _BoundArgs = {std::tuple<int>}; typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type = std::_Bind<SQLite::Statement(std::tuple<int>)>]’
/home/travis/build/SRombauts/SQLiteCpp/include/SQLiteCpp/ExecuteMany.h:84:9: required from ‘void SQLite::bind_exec(SQLite::Statement&, std::tuple<_Tps ...>&&) [with Types = {int}]’
/home/travis/build/SRombauts/SQLiteCpp/include/SQLiteCpp/ExecuteMany.h:50:14: required from ‘void SQLite::execute_many(SQLite::Database&, const char*, Arg&&, Types&& ...) [with Arg = std::tuple<int>; Types = {std::tuple<int, const char*>, std::tuple<int, const char*>}]’
/home/travis/build/SRombauts/SQLiteCpp/tests/ExecuteMany_test.cpp:35:9: required from here
/usr/include/c++/9/functional:462:59: error: ‘SQLite::Statement::Statement(const SQLite::Statement&)’ is private within this context
462 | : _M_f(__f), _M_bound_args(std::forward<_Args>(__args)...)
| ^
In file included from /home/travis/build/SRombauts/SQLiteCpp/include/SQLiteCpp/Column.h:13,
from /home/travis/build/SRombauts/SQLiteCpp/include/SQLiteCpp/Database.h:13,
from /home/travis/build/SRombauts/SQLiteCpp/tests/ExecuteMany_test.cpp:13:
/home/travis/build/SRombauts/SQLiteCpp/include/SQLiteCpp/Statement.h:696:5: note: declared private here
696 | Statement(const Statement&);
引发此错误的代码如下:
template <typename Arg, typename... Types>
void execute_many(Database& aDatabase, const char* apQuery, Arg&& aArg, Types&&... aParams)
{
Statement query(aDatabase, apQuery);
bind_exec(query, std::forward<Arg>(aArg));
(void)std::initializer_list<int>
{
((void)reset_bind_exec(query, std::forward<Types>(aParams)), 0)...
};
}
template <typename TupleT>
void reset_bind_exec(Statement& apQuery, TupleT&& aTuple)
{
apQuery.reset();
bind_exec(apQuery, std::forward<TupleT>(aTuple));
}
template <typename TupleT>
void bind_exec(Statement& apQuery, TupleT&& aTuple)
{
bind(apQuery, std::forward<TupleT>(aTuple));
while (apQuery.executeStep()) {}
}
我对travis使用如下代码CI使用对应的编译器
matrix:
include:
- compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-9
env:
- CC=gcc-9
- CXX=g++-9
- CXXFLAGS="-std=c++17 -Wall -Wextra -pedantic"
before_install:
# coveralls test coverage:
- if [[ "$CXX" == "g++" ]]; then pip install --user cpp-coveralls ; fi
# scripts to run before build
before_script:
- gcc --version
- mkdir build
- cd build
- cmake -DCMAKE_BUILD_TYPE=Debug -DSQLITECPP_USE_GCOV=ON -DSQLITECPP_BUILD_EXAMPLES=ON -DSQLITECPP_BUILD_TESTS=ON ..
# build examples, and run tests (ie make & make test)
script:
- cmake --build .
- ctest --verbose --output-on-failure
class语句有一个私有的复制构造函数和赋值运算符,但我想知道为什么这会在这里引起任何问题,因为我没有复制语句"query"。特别是为什么这个问题只发生在带有 c++17 的 gcc-9.1.0 上(在我的本地机器上我使用 gcc-9.1.1 并且编译没有任何错误)。
一个更简单的例子是这样的:
#include <functional>
namespace SQLite
{
struct Statement
{
Statement() = default;
Statement(const Statement&) = delete;
};
template<class ...Args>
void bind( Statement& s, const Args& ... args )
{
}
template < typename T >
void test(T&& t)
{
Statement s;
bind( s, std::forward< T >( t ) );
}
}
int main()
{
std::tuple< int > t;
SQLite::test( t );
}
因为您的参数之一来自 std
命名空间,参数依赖查找将 std::bind
带入可用函数列表。 SQLite::bind
需要在调用之前转换为 const&
,因此 std::bind
是更好的匹配。
您有几个选项可以解决此问题:
- 明确调用
SQLite::bind
- 将
bind
的名称更改为标准库中不存在的名称(这可能是最佳选择,因为它可以阻止您的用户 运行 进入同一问题)
- 将
bind
的参数从 const Args& ... args
更改为 Args&& ... args
以删除转换
我使用 travis 测试我的代码。最近有人将 gcc9 添加到用于测试代码的编译器集中。虽然使用 gcc8(使用 c++14 和 c++17)和使用 c++14 的 gcc-9.1.0 编译一切正常,但使用 c++17 的 gcc-9.1.0 失败并出现以下错误:
/usr/include/c++/9/functional: In instantiation of ‘std::_Bind<_Functor(_Bound_args ...)>::_Bind(const _Functor&, _Args&& ...) [with _Args = {std::tuple<int>}; _Functor = SQLite::Statement; _Bound_args = {std::tuple<int>}]’:
/usr/include/c++/9/functional:811:38: required from ‘typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type std::bind(_Func&&, _BoundArgs&& ...) [with _Func = SQLite::Statement&; _BoundArgs = {std::tuple<int>}; typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type = std::_Bind<SQLite::Statement(std::tuple<int>)>]’
/home/travis/build/SRombauts/SQLiteCpp/include/SQLiteCpp/ExecuteMany.h:84:9: required from ‘void SQLite::bind_exec(SQLite::Statement&, std::tuple<_Tps ...>&&) [with Types = {int}]’
/home/travis/build/SRombauts/SQLiteCpp/include/SQLiteCpp/ExecuteMany.h:50:14: required from ‘void SQLite::execute_many(SQLite::Database&, const char*, Arg&&, Types&& ...) [with Arg = std::tuple<int>; Types = {std::tuple<int, const char*>, std::tuple<int, const char*>}]’
/home/travis/build/SRombauts/SQLiteCpp/tests/ExecuteMany_test.cpp:35:9: required from here
/usr/include/c++/9/functional:462:59: error: ‘SQLite::Statement::Statement(const SQLite::Statement&)’ is private within this context
462 | : _M_f(__f), _M_bound_args(std::forward<_Args>(__args)...)
| ^
In file included from /home/travis/build/SRombauts/SQLiteCpp/include/SQLiteCpp/Column.h:13,
from /home/travis/build/SRombauts/SQLiteCpp/include/SQLiteCpp/Database.h:13,
from /home/travis/build/SRombauts/SQLiteCpp/tests/ExecuteMany_test.cpp:13:
/home/travis/build/SRombauts/SQLiteCpp/include/SQLiteCpp/Statement.h:696:5: note: declared private here
696 | Statement(const Statement&);
引发此错误的代码如下:
template <typename Arg, typename... Types>
void execute_many(Database& aDatabase, const char* apQuery, Arg&& aArg, Types&&... aParams)
{
Statement query(aDatabase, apQuery);
bind_exec(query, std::forward<Arg>(aArg));
(void)std::initializer_list<int>
{
((void)reset_bind_exec(query, std::forward<Types>(aParams)), 0)...
};
}
template <typename TupleT>
void reset_bind_exec(Statement& apQuery, TupleT&& aTuple)
{
apQuery.reset();
bind_exec(apQuery, std::forward<TupleT>(aTuple));
}
template <typename TupleT>
void bind_exec(Statement& apQuery, TupleT&& aTuple)
{
bind(apQuery, std::forward<TupleT>(aTuple));
while (apQuery.executeStep()) {}
}
我对travis使用如下代码CI使用对应的编译器
matrix:
include:
- compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-9
env:
- CC=gcc-9
- CXX=g++-9
- CXXFLAGS="-std=c++17 -Wall -Wextra -pedantic"
before_install:
# coveralls test coverage:
- if [[ "$CXX" == "g++" ]]; then pip install --user cpp-coveralls ; fi
# scripts to run before build
before_script:
- gcc --version
- mkdir build
- cd build
- cmake -DCMAKE_BUILD_TYPE=Debug -DSQLITECPP_USE_GCOV=ON -DSQLITECPP_BUILD_EXAMPLES=ON -DSQLITECPP_BUILD_TESTS=ON ..
# build examples, and run tests (ie make & make test)
script:
- cmake --build .
- ctest --verbose --output-on-failure
class语句有一个私有的复制构造函数和赋值运算符,但我想知道为什么这会在这里引起任何问题,因为我没有复制语句"query"。特别是为什么这个问题只发生在带有 c++17 的 gcc-9.1.0 上(在我的本地机器上我使用 gcc-9.1.1 并且编译没有任何错误)。
一个更简单的例子是这样的:
#include <functional>
namespace SQLite
{
struct Statement
{
Statement() = default;
Statement(const Statement&) = delete;
};
template<class ...Args>
void bind( Statement& s, const Args& ... args )
{
}
template < typename T >
void test(T&& t)
{
Statement s;
bind( s, std::forward< T >( t ) );
}
}
int main()
{
std::tuple< int > t;
SQLite::test( t );
}
因为您的参数之一来自 std
命名空间,参数依赖查找将 std::bind
带入可用函数列表。 SQLite::bind
需要在调用之前转换为 const&
,因此 std::bind
是更好的匹配。
您有几个选项可以解决此问题:
- 明确调用
SQLite::bind
- 将
bind
的名称更改为标准库中不存在的名称(这可能是最佳选择,因为它可以阻止您的用户 运行 进入同一问题) - 将
bind
的参数从const Args& ... args
更改为Args&& ... args
以删除转换