我想做一件简单的事情:
template <typename P>
void DoUntil(P predicate = [] { return false; });
显然这不起作用 - 我必须使用模板参数:
int main() { DoUntil(); }
但是这句话也不起作用--Clang给出了一个错误:
错误:没有匹配函数来调用...
注意:候选模板被忽略:无法推断模板参数&#39; P&#39;
如果我在没有参数的情况下调用该函数,那么编译器无法从默认参数中推断出类型:
std::function<>
我不想以任何方式使用D:\trydjango\src>python manage.py makemigrations
No changes detected
D:\trydjango\src>python manage.py migrate
Operations to perform:
Apply all migrations: contenttypes, auth, sessions, admin, posts
Running migrations:
Rendering model states... DONE
Applying posts.0009_auto_20170213_1754...Traceback (most recent call last):
File "manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "C:\python35\lib\site-packages\django\core\management\__init__.py", line
350, in execute_from_command_line
utility.execute()
File "C:\python35\lib\site-packages\django\core\management\__init__.py", line
342, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "C:\python35\lib\site-packages\django\core\management\base.py", line 348,
in run_from_argv
self.execute(*args, **cmd_options)
File "C:\python35\lib\site-packages\django\core\management\base.py", line 399,
in execute
output = self.handle(*args, **options)
File "C:\python35\lib\site-packages\django\core\management\commands\migrate.py
", line 200, in handle
executor.migrate(targets, plan, fake=fake, fake_initial=fake_initial)
File "C:\python35\lib\site-packages\django\db\migrations\executor.py", line 92
, in migrate
self._migrate_all_forwards(plan, full_plan, fake=fake, fake_initial=fake_ini
tial)
File "C:\python35\lib\site-packages\django\db\migrations\executor.py", line 12
1, in _migrate_all_forwards
state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_
initial)
File "C:\python35\lib\site-packages\django\db\migrations\executor.py", line 19
8, in apply_migration
state = migration.apply(state, schema_editor)
File "C:\python35\lib\site-packages\django\db\migrations\migration.py", line 1
23, in apply
operation.database_forwards(self.app_label, schema_editor, old_state, projec
t_state)
File "C:\python35\lib\site-packages\django\db\migrations\operations\fields.py"
, line 62, in database_forwards
field,
File "C:\python35\lib\site-packages\django\db\backends\sqlite3\schema.py", lin
e 221, in add_field
self._remake_table(model, create_fields=[field])
File "C:\python35\lib\site-packages\django\db\backends\sqlite3\schema.py", lin
e 103, in _remake_table
self.effective_default(field)
File "C:\python35\lib\site-packages\django\db\backends\base\schema.py", line 2
10, in effective_default
default = field.get_db_prep_save(default, self.connection)
File "C:\python35\lib\site-packages\django\db\models\fields\__init__.py", line
728, in get_db_prep_save
prepared=False)
File "C:\python35\lib\site-packages\django\db\models\fields\__init__.py", line
1461, in get_db_prep_value
value = self.get_prep_value(value)
File "C:\python35\lib\site-packages\django\db\models\fields\__init__.py", line
1440, in get_prep_value
value = super(DateTimeField, self).get_prep_value(value)
File "C:\python35\lib\site-packages\django\db\models\fields\__init__.py", line
1296, in get_prep_value
return self.to_python(value)
File "C:\python35\lib\site-packages\django\db\models\fields\__init__.py", line
1399, in to_python
parsed = parse_datetime(value)
File "C:\python35\lib\site-packages\django\utils\dateparse.py", line 93, in pa
rse_datetime
match = datetime_re.match(value)
TypeError: expected string or bytes-like object
D:\trydjango\src>
。
我的问题还有其他可能的解决方案吗?
答案 0 :(得分:8)
使用函数重载而不是默认参数功能。创建一个除模板函数之外不带参数的非模板函数:
void DoUntil() ;
template <typename P>
void DoUntil(P predicate) ;
无参数版本只需使用您想用作默认谓词的lambda调用模板版本:
void DoUntil() { DoUntil([] { return false; }); }
您的原始方法存在的问题是,您通过指定默认参数值尝试提供默认的模板专门化,但未指定默认的模板类型。即使没有涉及lambdas,以下内容也不会起作用,因为T
没有默认类型,即使t
有默认值:
template <typename T>
void Foo(T t = 3);
需要的是使用T
为<typename T = int>
指定默认类型。
如WhiZTiM的回答所述,涉及lambda函数的案例的默认类型必须使用decltype
推导出来。这当然是因为lambda具有只有编译器才知道的唯一类型。
答案 1 :(得分:4)
lambda是一个没有默认构造函数的匿名类型(原因,如果可用,你可以使用它的复制/移动构造函数)。如果你必须采用lambda方式,你可以这样做:
namespace detail{ auto predicate = [] { return false; }; }
template <typename P = decltype(detail::predicate)>
void DoUntil(P pred = detail::predicate);
而不是试图摆弄 lambdas 。你可以走老路:
namespace detail{
struct DefaultPredicate{ bool operator()() const { return false; } };
}
template <typename P = detail::DefaultPredicate>
void DoUntil(P predicate = P{});
或者更好的是Kyle Strand answered。